diff options
| author | RoshanCyriac <roshancyriac.k@gmail.com> | 2025-07-09 17:21:38 +0530 |
|---|---|---|
| committer | RoshanCyriac <roshancyriac.k@gmail.com> | 2025-07-09 17:21:38 +0530 |
| commit | 816a8d16a1454a6c0dc4d1fc61b8cdff781473d5 (patch) | |
| tree | 568c2bab21be0174d483f960e7c14cceba39ced2 | |
initial
| -rw-r--r-- | .gitignore | 24 | ||||
| -rw-r--r-- | README.md | 12 | ||||
| -rw-r--r-- | eslint.config.js | 29 | ||||
| -rw-r--r-- | index.html | 18 | ||||
| -rw-r--r-- | package-lock.json | 2618 | ||||
| -rw-r--r-- | package.json | 34 | ||||
| -rw-r--r-- | src/App.css | 147 | ||||
| -rw-r--r-- | src/App.jsx | 106 | ||||
| -rw-r--r-- | src/ProjectCard.jsx | 25 | ||||
| -rw-r--r-- | src/ProjectsSection.jsx | 41 | ||||
| -rw-r--r-- | src/ProjectsSection.module.css | 80 | ||||
| -rw-r--r-- | src/components/CommandPalette.jsx | 136 | ||||
| -rw-r--r-- | src/components/MatrixRain.jsx | 76 | ||||
| -rw-r--r-- | src/components/Navigation.jsx | 36 | ||||
| -rw-r--r-- | src/components/RetroTerminal.jsx | 98 | ||||
| -rw-r--r-- | src/components/RetroTerminal.module.css | 104 | ||||
| -rw-r--r-- | src/components/ScrollAnimations.jsx | 102 | ||||
| -rw-r--r-- | src/components/Terminal.jsx | 121 | ||||
| -rw-r--r-- | src/index.css | 683 | ||||
| -rw-r--r-- | src/main.jsx | 10 | ||||
| -rw-r--r-- | src/pages/About.jsx | 302 | ||||
| -rw-r--r-- | src/pages/Contact.jsx | 336 | ||||
| -rw-r--r-- | src/pages/Events.jsx | 325 | ||||
| -rw-r--r-- | src/pages/Home.jsx | 58 | ||||
| -rw-r--r-- | src/pages/Projects.jsx | 309 | ||||
| -rw-r--r-- | src/pages/Resources.jsx | 323 | ||||
| -rw-r--r-- | src/pages/Team.jsx | 257 | ||||
| -rw-r--r-- | vite.config.js | 7 |
28 files changed, 6417 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/README.md b/README.md new file mode 100644 index 0000000..7059a96 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..cee1e2c --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,29 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{js,jsx}'], + extends: [ + js.configs.recommended, + reactHooks.configs['recommended-latest'], + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + rules: { + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + }, + }, +]) diff --git a/index.html b/index.html new file mode 100644 index 0000000..af158ce --- /dev/null +++ b/index.html @@ -0,0 +1,18 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta name="description" content="FOSSEE Club - Free and Open Source Software for Education" /> + <meta name="keywords" content="FOSSEE, Open Source, Linux, Programming, Education" /> + <title>FOSSEE Club - Free and Open Source Software for Education</title> + <link rel="preconnect" href="https://fonts.googleapis.com"> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> + <link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300;400;500;600;700&family=JetBrains+Mono:wght@100;200;300;400;500;600;700;800&display=swap" rel="stylesheet"> + </head> + <body> + <div id="root"></div> + <script type="module" src="/src/main.jsx"></script> + </body> +</html> diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3e6e28c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2618 @@ +{ + "name": "fossee-club", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "fossee-club", + "version": "1.0.0", + "dependencies": { + "framer-motion": "^12.23.0", + "lucide-react": "^0.468.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-router-dom": "^6.28.0", + "react-syntax-highlighter": "^15.5.0", + "react-type-animation": "^3.2.0", + "xterm": "^5.3.0" + }, + "devDependencies": { + "@eslint/js": "^9.30.1", + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@types/react-syntax-highlighter": "^15.5.11", + "@vitejs/plugin-react": "^4.6.0", + "eslint": "^9.30.1", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.3.0", + "vite": "^4.4.9" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "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, + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", + "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.6", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", + "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.28.0", + "@babel/types": "^7.28.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "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, + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "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, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "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, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", + "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "dev": true, + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.28.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", + "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", + "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, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", + "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.0.tgz", + "integrity": "sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", + "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.30.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.1.tgz", + "integrity": "sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz", + "integrity": "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==", + "dev": true, + "dependencies": { + "@eslint/core": "^0.15.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@remix-run/router": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz", + "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.19", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.19.tgz", + "integrity": "sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", + "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true + }, + "node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/react": { + "version": "19.1.8", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz", + "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==", + "dev": true, + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.1.6", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.6.tgz", + "integrity": "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==", + "dev": true, + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@types/react-syntax-highlighter": { + "version": "15.5.13", + "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.13.tgz", + "integrity": "sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.6.0.tgz", + "integrity": "sha512-5Kgff+m8e2PB+9j51eGHEpn5kUzRKH2Ry0qGoe8ItJg7pqnkPrYPkDQZGgGmTa0EGarHrkjLvOdU3b1fzI8otQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.19", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001727", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", + "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.180", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.180.tgz", + "integrity": "sha512-ED+GEyEh3kYMwt2faNmgMB0b8O5qtATGgR4RmRsIp4T6p7B8vdMbIedYndnvZfsaXvSzegtpfqRMDNCjjiSduA==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.30.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.30.1.tgz", + "integrity": "sha512-zmxXPNMOXmwm9E0yQLi5uqXHs7uq2UIiqEKo3Gq+3fwo1XrJ+hijAZImyF7hclW3E6oHz43Yk3RP8at6OTKflQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", + "@eslint/core": "^0.14.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.30.1", + "@eslint/plugin-kit": "^0.3.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz", + "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==", + "dev": true, + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/framer-motion": { + "version": "12.23.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.0.tgz", + "integrity": "sha512-xf6NxTGAyf7zR4r2KlnhFmsRfKIbjqeBupEDBAaEtVIBJX96sAon00kMlsKButSIRwPSHjbRrAPnYdJJ9kyhbA==", + "dependencies": { + "motion-dom": "^12.22.0", + "motion-utils": "^12.19.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz", + "integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "engines": { + "node": "*" + } + }, + "node_modules/highlightjs-vue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz", + "integrity": "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lowlight": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "dependencies": { + "fault": "^1.0.0", + "highlight.js": "~10.7.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.468.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.468.0.tgz", + "integrity": "sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA==", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/motion-dom": { + "version": "12.22.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.22.0.tgz", + "integrity": "sha512-ooH7+/BPw9gOsL9VtPhEJHE2m4ltnhMlcGMhEqA0YGNhKof7jdaszvsyThXI6LVIKshJUZ9/CP6HNqQhJfV7kw==", + "dependencies": { + "motion-utils": "^12.19.0" + } + }, + "node_modules/motion-utils": { + "version": "12.19.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.19.0.tgz", + "integrity": "sha512-BuFTHINYmV07pdWs6lj6aI63vr2N4dg0vR+td0rtrdpWOhBzIkEklZyLcvKBoEtwSqx8Jg06vUB5RS0xDiUybw==" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "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, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "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 + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "peer": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "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==", + "peer": true + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.30.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.1.tgz", + "integrity": "sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ==", + "dependencies": { + "@remix-run/router": "1.23.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.1.tgz", + "integrity": "sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==", + "dependencies": { + "@remix-run/router": "1.23.0", + "react-router": "6.30.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-syntax-highlighter": { + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.6.1.tgz", + "integrity": "sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "highlight.js": "^10.4.1", + "highlightjs-vue": "^1.0.0", + "lowlight": "^1.17.0", + "prismjs": "^1.27.0", + "refractor": "^3.6.0" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, + "node_modules/react-type-animation": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-type-animation/-/react-type-animation-3.2.0.tgz", + "integrity": "sha512-WXTe0i3rRNKjmggPvT5ntye1QBt0ATGbijeW6V3cQe2W0jaMABXXlPPEdtofnS9tM7wSRHchEvI9SUw+0kUohw==", + "peerDependencies": { + "prop-types": "^15.5.4", + "react": ">= 15.0.0", + "react-dom": ">= 15.0.0" + } + }, + "node_modules/refractor": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", + "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", + "dependencies": { + "hastscript": "^6.0.0", + "parse-entities": "^2.0.0", + "prismjs": "~1.27.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/prismjs": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", + "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/resolve-from": { + "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, + "engines": { + "node": ">=4" + } + }, + "node_modules/rollup": { + "version": "3.29.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", + "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", + "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", + "dev": true, + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/xterm": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz", + "integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==", + "deprecated": "This package is now deprecated. Move to @xterm/xterm instead." + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..3df314a --- /dev/null +++ b/package.json @@ -0,0 +1,34 @@ +{ + "name": "fossee-club", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "framer-motion": "^12.23.0", + "lucide-react": "^0.468.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-router-dom": "^6.28.0", + "react-syntax-highlighter": "^15.5.0", + "react-type-animation": "^3.2.0", + "xterm": "^5.3.0" + }, + "devDependencies": { + "@eslint/js": "^9.30.1", + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@types/react-syntax-highlighter": "^15.5.11", + "@vitejs/plugin-react": "^4.6.0", + "eslint": "^9.30.1", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.3.0", + "vite": "^4.4.9" + } +} diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..ab24914 --- /dev/null +++ b/src/App.css @@ -0,0 +1,147 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} + +.terminalWindow { + position: fixed; + z-index: 9999; + left: 100px; + top: 100px; + width: 600px; + height: 400px; + background: #181825; + color: #e0e0e0; + font-family: 'Fira Mono', 'Consolas', 'Courier New', monospace; + border: 4px double #fff; + border-radius: 8px 8px 0 0; + display: flex; + flex-direction: column; + box-shadow: 0 8px 32px rgba(0,0,0,0.5); + overflow: hidden; +} + +.terminalHeader { + background: linear-gradient(90deg, #22223b 80%, #6c63ff 100%); + color: #fff; + padding: 0.5em 1em; + font-weight: bold; + display: flex; + align-items: center; + cursor: move; + user-select: none; + border-bottom: 2px solid #6c63ff; + z-index: 2; /* Ensure header is above content */ +} + +.terminalTitle { + flex: 1; + letter-spacing: 2px; + font-size: 1.1em; +} + +.closeBtn { + background: #ff5f56; + border: none; + color: #fff; + font-size: 1.2em; + width: 2em; + height: 2em; + border-radius: 50%; + cursor: pointer; + margin-left: 0.5em; + transition: background 0.2s; +} +.closeBtn:hover { + background: #ff2d00; +} + +.terminalOutput { + flex: 1; + background: #181825; + color: #e0e0e0; + padding: 1em; + font-size: 1em; + overflow-y: auto; + border-bottom: 2px solid #6c63ff; + word-break: break-word; + z-index: 1; +} + +.terminalLine { + white-space: pre-wrap; + line-height: 1.5; +} + +.terminalInputBar { + display: flex; + align-items: center; + background: #22223b; + padding: 0.5em 1em; + border-top: 2px solid #6c63ff; + z-index: 1; +} + +.prompt { + color: #6c63ff; + font-weight: bold; + margin-right: 0.5em; +} + +.terminalInput { + flex: 1; + background: transparent; + border: none; + color: #e0e0e0; + font-family: inherit; + font-size: 1em; + outline: none; +} + +.resizer { + position: absolute; + right: 0; + bottom: 0; + width: 18px; + height: 18px; + background: linear-gradient(135deg, transparent 60%, #6c63ff 100%); + cursor: se-resize; +} diff --git a/src/App.jsx b/src/App.jsx new file mode 100644 index 0000000..0fdd0ec --- /dev/null +++ b/src/App.jsx @@ -0,0 +1,106 @@ +import React, { useState, useEffect } from 'react'; +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; +import { motion, AnimatePresence } from 'framer-motion'; +import Navigation from './components/Navigation'; +import Home from './pages/Home'; +import About from './pages/About'; +import Events from './pages/Events'; +import Projects from './pages/Projects'; +import Resources from './pages/Resources'; +import Team from './pages/Team'; +import Contact from './pages/Contact'; +import MatrixRain from './components/MatrixRain'; +import CommandPalette from './components/CommandPalette'; +import ScrollAnimations from './components/ScrollAnimations'; +import RetroTerminal from './components/RetroTerminal'; +import './App.css'; + +function App() { + const [commandPaletteOpen, setCommandPaletteOpen] = useState(false); + const [isLoading, setIsLoading] = useState(true); + const [scrollDirection, setScrollDirection] = useState('down'); + const [lastScrollY, setLastScrollY] = useState(0); + const [terminalOpen, setTerminalOpen] = useState(false); + + useEffect(() => { + // Simulate loading time for terminal boot sequence + const timer = setTimeout(() => { + setIsLoading(false); + }, 2000); + + return () => clearTimeout(timer); + }, []); + + useEffect(() => { + const handleKeyDown = (e) => { + if (e.ctrlKey && e.key === 'k') { + e.preventDefault(); + setCommandPaletteOpen(true); + } + if (e.ctrlKey && e.key === '`') { + e.preventDefault(); + setTerminalOpen((open) => !open); + } + if (e.key === 'Escape') { + setCommandPaletteOpen(false); + setTerminalOpen(false); + } + }; + + // Scroll direction detection + const handleScroll = () => { + const currentScrollY = window.scrollY; + setScrollDirection(currentScrollY > lastScrollY ? 'down' : 'up'); + setLastScrollY(currentScrollY); + }; + + window.addEventListener('keydown', handleKeyDown); + window.addEventListener('scroll', handleScroll); + + return () => { + window.removeEventListener('keydown', handleKeyDown); + window.removeEventListener('scroll', handleScroll); + }; + }, [lastScrollY]); + + if (isLoading) { + return ( + <div className="loading-screen"> + <div className="terminal"> + <div className="terminal-prompt">root@fossee:~$</div> + <div className="typewriter">Initializing FOSSEE Club System...</div> + <div className="loading mt-4"></div> + </div> + </div> + ); + } + + return ( + <Router> + <div className="App"> + <MatrixRain /> + <ScrollAnimations /> + <Navigation /> + <RetroTerminal visible={terminalOpen} onClose={() => setTerminalOpen(false)} /> + <AnimatePresence mode="wait"> + <Routes> + <Route path="/" element={<Home />} /> + <Route path="/about" element={<About />} /> + <Route path="/events" element={<Events />} /> + <Route path="/projects" element={<Projects />} /> + <Route path="/resources" element={<Resources />} /> + <Route path="/team" element={<Team />} /> + <Route path="/contact" element={<Contact />} /> + </Routes> + </AnimatePresence> + + <CommandPalette + isOpen={commandPaletteOpen} + onClose={() => setCommandPaletteOpen(false)} + /> + </div> + </Router> + ); +} + +export default App; diff --git a/src/ProjectCard.jsx b/src/ProjectCard.jsx new file mode 100644 index 0000000..e450fc2 --- /dev/null +++ b/src/ProjectCard.jsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { motion } from 'framer-motion'; +import styles from './ProjectsSection.module.css'; + +const ProjectCard = ({ name, year, info, link, color }) => ( + <motion.div + className={styles.projectCard} + whileHover={{ scale: 1.05, boxShadow: '0 8px 32px rgba(0,255,174,0.2)' }} + initial={{ opacity: 0 }} + animate={{ opacity: 1 }} + transition={{ duration: 0.5 }} + style={{ borderColor: color }} + > + <div className={styles.cardHeader} style={{ background: color }}> + <span className={styles.cardYear}>{year}</span> + <span className={styles.cardName}>{name}</span> + </div> + <div className={styles.cardInfo}>{info}</div> + <a className={styles.cardLink} href={link} target="_blank" rel="noopener noreferrer"> + VISIT SITE + </a> + </motion.div> +); + +export default ProjectCard;
\ No newline at end of file diff --git a/src/ProjectsSection.jsx b/src/ProjectsSection.jsx new file mode 100644 index 0000000..7524b43 --- /dev/null +++ b/src/ProjectsSection.jsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { motion } from 'framer-motion'; +import ProjectCard from './ProjectCard'; +import styles from './ProjectsSection.module.css'; + +const projects = [ + { + name: 'PLAYBOOK JOURNAL', + year: 2022, + info: 'A collaborative playbook for cross-border journalists. Design: Loonatiks Design Crew. Tech: GatsbyJS, Canvas, MatterJS, React-Spring.', + link: 'https://playbook.n-ost.org/', + color: '#00ffae', + }, + { + name: 'MIAO', + year: 2023, + info: 'A startup providing global users with an exceptionally entertaining experience through innovative gaming products and services.', + link: '#', + color: '#00ffae', + }, +]; + +const ProjectsSection = () => ( + <section className={styles.section}> + <motion.h1 + className={styles.heading} + initial={{ opacity: 0, y: -50 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8 }} + > + PROJECTS + </motion.h1> + <div className={styles.grid}> + {projects.map((project, idx) => ( + <ProjectCard key={idx} {...project} /> + ))} + </div> + </section> +); + +export default ProjectsSection;
\ No newline at end of file diff --git a/src/ProjectsSection.module.css b/src/ProjectsSection.module.css new file mode 100644 index 0000000..4741280 --- /dev/null +++ b/src/ProjectsSection.module.css @@ -0,0 +1,80 @@ +.section { + background: #000; + min-height: 100vh; + padding: 60px 0; + font-family: 'IBM Plex Mono', monospace; +} + +.heading { + color: #fff; + font-size: 6vw; + letter-spacing: 0.1em; + text-align: left; + margin-bottom: 40px; + font-weight: 700; +} + +.grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); + gap: 40px; + max-width: 1200px; + margin: 0 auto; +} + +.card { + background: #111; + border: 2px solid #00ffae; + border-radius: 16px; + padding: 32px 24px; + color: #fff; + transition: box-shadow 0.3s; + display: flex; + flex-direction: column; + min-height: 320px; + position: relative; +} + +.cardHeader { + display: flex; + flex-direction: column; + background: #00ffae; + color: #000; + padding: 12px 16px; + border-radius: 8px 8px 0 0; + margin-bottom: 18px; +} + +.cardYear { + font-size: 1.1rem; + font-weight: 600; + letter-spacing: 0.08em; +} + +.cardName { + font-size: 2rem; + font-weight: 700; + letter-spacing: 0.1em; +} + +.cardInfo { + font-size: 1rem; + margin-bottom: 24px; + color: #b2fff6; + flex: 1; +} + +.cardLink { + align-self: flex-end; + color: #00ffae; + font-size: 1.1rem; + text-decoration: none; + font-weight: 700; + border-bottom: 2px solid #00ffae; + transition: color 0.2s, border-color 0.2s; +} + +.cardLink:hover { + color: #fff; + border-color: #fff; +}
\ No newline at end of file diff --git a/src/components/CommandPalette.jsx b/src/components/CommandPalette.jsx new file mode 100644 index 0000000..decde36 --- /dev/null +++ b/src/components/CommandPalette.jsx @@ -0,0 +1,136 @@ +import React, { useState, useEffect, useRef } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { motion, AnimatePresence } from 'framer-motion'; +import { Search, Terminal, FileText, Users, Calendar, Code, BookOpen, Mail } from 'lucide-react'; + +const CommandPalette = ({ isOpen, onClose }) => { + const [query, setQuery] = useState(''); + const [selectedIndex, setSelectedIndex] = useState(0); + const inputRef = useRef(null); + const navigate = useNavigate(); + + const commands = [ + { id: 'home', label: 'Go to Home', icon: Terminal, path: '/' }, + { id: 'about', label: 'About FOSSEE', icon: FileText, path: '/about' }, + { id: 'events', label: 'View Events', icon: Calendar, path: '/events' }, + { id: 'projects', label: 'Browse Projects', icon: Code, path: '/projects' }, + { id: 'resources', label: 'Learning Resources', icon: BookOpen, path: '/resources' }, + { id: 'team', label: 'Meet the Team', icon: Users, path: '/team' }, + { id: 'contact', label: 'Contact Us', icon: Mail, path: '/contact' }, + ]; + + const filteredCommands = commands.filter(command => + command.label.toLowerCase().includes(query.toLowerCase()) + ); + + useEffect(() => { + if (isOpen) { + inputRef.current?.focus(); + setQuery(''); + setSelectedIndex(0); + } + }, [isOpen]); + + useEffect(() => { + const handleKeyDown = (e) => { + if (!isOpen) return; + + switch (e.key) { + case 'ArrowDown': + e.preventDefault(); + setSelectedIndex(prev => + prev < filteredCommands.length - 1 ? prev + 1 : 0 + ); + break; + case 'ArrowUp': + e.preventDefault(); + setSelectedIndex(prev => + prev > 0 ? prev - 1 : filteredCommands.length - 1 + ); + break; + case 'Enter': + e.preventDefault(); + if (filteredCommands[selectedIndex]) { + executeCommand(filteredCommands[selectedIndex]); + } + break; + } + }; + + document.addEventListener('keydown', handleKeyDown); + return () => document.removeEventListener('keydown', handleKeyDown); + }, [isOpen, selectedIndex, filteredCommands]); + + const executeCommand = (command) => { + navigate(command.path); + onClose(); + }; + + if (!isOpen) return null; + + return ( + <AnimatePresence> + <motion.div + initial={{ opacity: 0 }} + animate={{ opacity: 1 }} + exit={{ opacity: 0 }} + className="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4" + onClick={onClose} + > + <motion.div + initial={{ scale: 0.9, opacity: 0 }} + animate={{ scale: 1, opacity: 1 }} + exit={{ scale: 0.9, opacity: 0 }} + className="command-palette" + onClick={(e) => e.stopPropagation()} + > + <div className="flex items-center mb-4"> + <Search className="w-5 h-5 text-green mr-2" /> + <input + ref={inputRef} + type="text" + placeholder="Type a command or search..." + value={query} + onChange={(e) => setQuery(e.target.value)} + className="flex-1 bg-transparent border-none text-green font-mono text-base outline-none" + /> + </div> + + <div className="space-y-1 max-h-64 overflow-y-auto"> + {filteredCommands.length > 0 ? ( + filteredCommands.map((command, index) => ( + <motion.button + key={command.id} + className={`w-full text-left p-2 rounded flex items-center space-x-3 transition-colors ${ + index === selectedIndex + ? 'bg-green bg-opacity-20 text-green' + : 'text-white hover:bg-gray hover:bg-opacity-20' + }`} + onClick={() => executeCommand(command)} + whileHover={{ scale: 1.02 }} + whileTap={{ scale: 0.98 }} + > + <command.icon className="w-4 h-4" /> + <span>{command.label}</span> + </motion.button> + )) + ) : ( + <div className="text-gray text-center py-4"> + No commands found for "{query}" + </div> + )} + </div> + + <div className="mt-4 pt-4 border-t border-light-gray text-xs text-gray"> + <div className="flex justify-between"> + <span>↑↓ Navigate • Enter Execute • Esc Close</span> + <span>Ctrl+K to open</span> + </div> + </div> + </motion.div> + </motion.div> + </AnimatePresence> + ); +}; + +export default CommandPalette;
\ No newline at end of file diff --git a/src/components/MatrixRain.jsx b/src/components/MatrixRain.jsx new file mode 100644 index 0000000..b5c2a45 --- /dev/null +++ b/src/components/MatrixRain.jsx @@ -0,0 +1,76 @@ +import React, { useEffect, useRef } from 'react'; + +const MatrixRain = () => { + const canvasRef = useRef(null); + + useEffect(() => { + const canvas = canvasRef.current; + const ctx = canvas.getContext('2d'); + + // Set canvas size + const resizeCanvas = () => { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + }; + + resizeCanvas(); + window.addEventListener('resize', resizeCanvas); + + // Matrix characters + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%^&*()_+-=[]{}|;:,.<>?'; + const charArray = chars.split(''); + + // Rain drops + const drops = []; + const fontSize = 14; + const columns = canvas.width / fontSize; + + // Initialize drops + for (let i = 0; i < columns; i++) { + drops[i] = 1; + } + + // Animation function + const draw = () => { + // Semi-transparent background to create fade effect + ctx.fillStyle = 'rgba(0, 0, 0, 0.05)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + // Draw characters + ctx.fillStyle = '#00ff41'; + ctx.font = `${fontSize}px 'Fira Code'`; + + for (let i = 0; i < drops.length; i++) { + // Random character + const char = charArray[Math.floor(Math.random() * charArray.length)]; + + // Draw character + ctx.fillText(char, i * fontSize, drops[i] * fontSize); + + // Reset drop when it reaches bottom + if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) { + drops[i] = 0; + } + + // Move drop down + drops[i]++; + } + }; + + // Animation loop + const interval = setInterval(draw, 50); + + return () => { + clearInterval(interval); + window.removeEventListener('resize', resizeCanvas); + }; + }, []); + + return ( + <div className="matrix-rain"> + <canvas ref={canvasRef} /> + </div> + ); +}; + +export default MatrixRain;
\ No newline at end of file diff --git a/src/components/Navigation.jsx b/src/components/Navigation.jsx new file mode 100644 index 0000000..c3aae9a --- /dev/null +++ b/src/components/Navigation.jsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { Link, useLocation } from 'react-router-dom'; + +const Navigation = () => { + const location = useLocation(); + + const navItems = [ + { path: '/', label: 'Home' }, + { path: '/about', label: 'About' }, + { path: '/events', label: 'Events' }, + { path: '/projects', label: 'Projects' }, + { path: '/resources', label: 'Resources' }, + { path: '/team', label: 'Team' }, + { path: '/contact', label: 'Contact' }, + ]; + + return ( + <nav className="nav"> + <div className="container mx-auto px-4"> + <div className="flex justify-evenly items-center h-16 w-full"> + {navItems.map((item) => ( + <Link + key={item.path} + to={item.path} + className={`nav-link text-sm md:text-base ${location.pathname === item.path ? 'text-green' : ''}`} + > + {item.label} + </Link> + ))} + </div> + </div> + </nav> + ); +}; + +export default Navigation;
\ No newline at end of file diff --git a/src/components/RetroTerminal.jsx b/src/components/RetroTerminal.jsx new file mode 100644 index 0000000..f124789 --- /dev/null +++ b/src/components/RetroTerminal.jsx @@ -0,0 +1,98 @@ +import React, { useState, useRef, useEffect } from 'react'; +import styles from './RetroTerminal.module.css'; + +const COMMANDS = { + help: 'Available commands: help, clear, about', + about: 'FOSSSE CUSAT Terminal. Free and Open Source Software Society, Cochin University of Science and Technology.', +}; + +function getPrompt() { + return 'fossse@cusat $ '; +} + +function RetroTerminal({ visible, onClose }) { + const [history, setHistory] = useState([ + 'Welcome to FOSSSE CUSAT Terminal!', + 'For available commands, try "help".', + '', + `Last login: ${new Date().toLocaleDateString()}, ${new Date().toLocaleTimeString()}`, + '', + getPrompt(), + ]); + const [input, setInput] = useState(''); + const [size, setSize] = useState({ width: 600, height: 400 }); + const terminalRef = useRef(null); + const outputRef = useRef(null); + + useEffect(() => { + if (visible && outputRef.current) { + outputRef.current.scrollTop = outputRef.current.scrollHeight; + } + }, [history, visible]); + + function handleInput(e) { + setInput(e.target.value); + } + + function handleCommand(cmd) { + if (cmd.trim() === '') return; + if (cmd === 'clear') { + setHistory([getPrompt()]); + return; + } + const output = COMMANDS[cmd] || `Command not found: ${cmd}`; + setHistory((h) => [...h, cmd, output, '', getPrompt()]); + } + + function handleKeyDown(e) { + if (e.key === 'Enter') { + handleCommand(input); + setInput(''); + } + } + + function handleResize(e) { + e.preventDefault(); + function onMouseMove(ev) { + setSize((s) => ({ + width: Math.max(400, ev.clientX - (terminalRef.current?.getBoundingClientRect().left || 0)), + height: Math.max(200, ev.clientY - (terminalRef.current?.getBoundingClientRect().top || 0)), + })); + } + function onMouseUp() { + window.removeEventListener('mousemove', onMouseMove); + window.removeEventListener('mouseup', onMouseUp); + } + window.addEventListener('mousemove', onMouseMove); + window.addEventListener('mouseup', onMouseUp); + } + + if (!visible) return null; + + return ( + <div + ref={terminalRef} + className={styles.terminalWindow} + style={{ width: size.width, height: size.height }} + > + <div className={styles.terminalOutput} ref={outputRef}> + {history.map((line, i) => ( + <div key={i} className={styles.terminalLine}>{line}</div> + ))} + </div> + <div className={styles.terminalInputBar}> + <span className={styles.prompt}>{getPrompt()}</span> + <input + className={styles.terminalInput} + value={input} + onChange={handleInput} + onKeyDown={handleKeyDown} + autoFocus + /> + </div> + <div className={styles.resizer} onMouseDown={handleResize} /> + </div> + ); +} + +export default RetroTerminal;
\ No newline at end of file diff --git a/src/components/RetroTerminal.module.css b/src/components/RetroTerminal.module.css new file mode 100644 index 0000000..e5dfab2 --- /dev/null +++ b/src/components/RetroTerminal.module.css @@ -0,0 +1,104 @@ +.terminalWindow { + position: fixed; + z-index: 9999; + left: 100px; + top: 100px; + width: 600px; + height: 400px; + background: #181825; + color: #e0e0e0; + font-family: 'Fira Mono', 'Consolas', 'Courier New', monospace; + border: 4px double #fff; + border-radius: 8px 8px 0 0; + display: flex; + flex-direction: column; + box-shadow: 0 8px 32px rgba(0,0,0,0.5); + overflow: hidden; +} + +.terminalHeader { + background: linear-gradient(90deg, #22223b 80%, #6c63ff 100%); + color: #fff; + padding: 0.5em 1em; + font-weight: bold; + display: flex; + align-items: center; + cursor: move; + user-select: none; + border-bottom: 2px solid #6c63ff; + z-index: 2; +} + +.terminalTitle { + flex: 1; + letter-spacing: 2px; + font-size: 1.1em; +} + +.closeBtn { + background: #ff5f56; + border: none; + color: #fff; + font-size: 1.2em; + width: 2em; + height: 2em; + border-radius: 50%; + cursor: pointer; + margin-left: 0.5em; + transition: background 0.2s; +} +.closeBtn:hover { + background: #ff2d00; +} + +.terminalOutput { + flex: 1; + background: #181825; + color: #e0e0e0; + padding: 1em; + font-size: 1em; + overflow-y: auto; + border-bottom: 2px solid #6c63ff; + word-break: break-word; + z-index: 1; +} + +.terminalLine { + white-space: pre-wrap; + line-height: 1.5; +} + +.terminalInputBar { + display: flex; + align-items: center; + background: #22223b; + padding: 0.5em 1em; + border-top: 2px solid #6c63ff; + z-index: 1; +} + +.prompt { + color: #6c63ff; + font-weight: bold; + margin-right: 0.5em; +} + +.terminalInput { + flex: 1; + background: transparent; + border: none; + color: #e0e0e0; + font-family: inherit; + font-size: 1em; + outline: none; +} + +.resizer { + position: absolute; + right: 0; + bottom: 0; + width: 18px; + height: 18px; + background: linear-gradient(135deg, transparent 60%, #6c63ff 100%); + cursor: se-resize; +}
\ No newline at end of file diff --git a/src/components/ScrollAnimations.jsx b/src/components/ScrollAnimations.jsx new file mode 100644 index 0000000..d6c2355 --- /dev/null +++ b/src/components/ScrollAnimations.jsx @@ -0,0 +1,102 @@ +import React, { useEffect, useRef } from 'react'; + +const ScrollAnimations = () => { + const scrollProgressRef = useRef(null); + const particlesRef = useRef(null); + + useEffect(() => { + // Scroll Progress Bar + const updateScrollProgress = () => { + const scrollTop = window.scrollY; + const docHeight = document.documentElement.scrollHeight - window.innerHeight; + const scrollPercent = (scrollTop / docHeight) * 100; + + if (scrollProgressRef.current) { + scrollProgressRef.current.style.width = `${scrollPercent}%`; + } + }; + + // Parallax Effect + const handleParallax = () => { + const scrolled = window.pageYOffset; + const parallaxElements = document.querySelectorAll('.parallax-slow, .parallax-medium, .parallax-fast'); + + parallaxElements.forEach(element => { + const speed = element.classList.contains('parallax-slow') ? 0.5 : + element.classList.contains('parallax-medium') ? 0.3 : 0.1; + const yPos = -(scrolled * speed); + element.style.setProperty('--parallax-y', `${yPos}px`); + }); + }; + + // Scroll Trigger Animations + const handleScrollTriggers = () => { + const triggers = document.querySelectorAll('.scroll-trigger, .scroll-fade-in, .scroll-slide-left, .scroll-slide-right, .scroll-scale-in'); + + triggers.forEach(trigger => { + const triggerTop = trigger.getBoundingClientRect().top; + const triggerBottom = trigger.getBoundingClientRect().bottom; + const windowHeight = window.innerHeight; + + if (triggerTop < windowHeight * 0.8 && triggerBottom > 0) { + trigger.classList.add('visible', 'triggered'); + } + }); + }; + + // Particle System + const createParticle = () => { + if (!particlesRef.current) return; + + const particle = document.createElement('div'); + particle.className = 'particle'; + particle.style.left = Math.random() * 100 + '%'; + particle.style.animationDuration = (Math.random() * 4 + 4) + 's'; + particle.style.animationDelay = Math.random() * 2 + 's'; + + particlesRef.current.appendChild(particle); + + // Remove particle after animation + setTimeout(() => { + if (particle.parentNode) { + particle.parentNode.removeChild(particle); + } + }, 8000); + }; + + // Initialize particle system + const particleInterval = setInterval(createParticle, 2000); + + // Event listeners + window.addEventListener('scroll', () => { + updateScrollProgress(); + handleParallax(); + handleScrollTriggers(); + }); + + // Initial call + updateScrollProgress(); + handleScrollTriggers(); + + return () => { + window.removeEventListener('scroll', () => { + updateScrollProgress(); + handleParallax(); + handleScrollTriggers(); + }); + clearInterval(particleInterval); + }; + }, []); + + return ( + <> + {/* Scroll Progress Bar */} + <div ref={scrollProgressRef} className="scroll-progress"></div> + + {/* Particle System */} + <div ref={particlesRef} className="particles"></div> + </> + ); +}; + +export default ScrollAnimations;
\ No newline at end of file diff --git a/src/components/Terminal.jsx b/src/components/Terminal.jsx new file mode 100644 index 0000000..db5c7b0 --- /dev/null +++ b/src/components/Terminal.jsx @@ -0,0 +1,121 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Terminal as XTerm } from 'xterm'; +import 'xterm/css/xterm.css'; + +const DATA = { + about: `FOSS CUSAT is a community of students passionate about open source software, Linux, and programming. Our mission is to promote FOSS philosophy and provide hands-on learning opportunities at CUSAT.`, + projects: `Projects:\n- Open Source Club Website\n- Linux Install Fest\n- FOSS Workshops\n- Community Contributions`, + team: `Team:\n- Alice (Lead)\n- Bob (Dev)\n- Carol (Design)\n- Dave (Events)`, + resources: `Resources:\n- https://fosscusat.in/resources\n- https://fosscusat.in/docs`, + events: `Upcoming Events:\n- Linux Bootcamp\n- Hackathon\n- Open Source Day`, + contact: `Contact us at: foss@cusat.ac.in`, + help: `Available commands: ls, cd <section>, about, projects, team, resources, events, contact, clear, help`, +}; + +const SECTIONS = ['home', 'about', 'projects', 'team', 'resources', 'events', 'contact']; + +const PROMPT_BASE = 'foss@cusat'; + +const Terminal = () => { + const xtermRef = useRef(null); + const termRef = useRef(null); + const [cwd, setCwd] = useState('home'); + + useEffect(() => { + if (!xtermRef.current) { + const term = new XTerm({ + theme: { + background: '#161b22', + foreground: '#00ff41', + cursor: '#00ff41', + }, + fontFamily: 'Fira Mono, JetBrains Mono, monospace', + fontSize: 16, + cursorBlink: true, + rows: 20, + }); + xtermRef.current = term; + term.open(termRef.current); + term.writeln('Welcome to the FOSS CUSAT Terminal!'); + term.writeln("Type 'help' to see available commands.\n"); + printPrompt(term, 'home'); + + let input = ''; + let currentDir = 'home'; + term.onKey(({ key, domEvent }) => { + if (domEvent.key === 'Enter') { + term.write('\r\n'); + handleCommand(input, term, currentDir, (newDir) => { + currentDir = newDir; + setCwd(newDir); + }); + input = ''; + setTimeout(() => printPrompt(term, currentDir), 10); + } else if (domEvent.key === 'Backspace') { + if (input.length > 0) { + input = input.slice(0, -1); + term.write('\b \b'); + } + } else if (domEvent.key.length === 1) { + input += key; + term.write(key); + } + }); + } + // Cleanup + return () => { + if (xtermRef.current) { + xtermRef.current.dispose(); + xtermRef.current = null; + } + }; + }, []); + + function printPrompt(term, dir) { + term.write(`\x1b[1;32m${PROMPT_BASE}:${dir === 'home' ? '~' : '/' + dir}$ \x1b[0m`); + } + + function handleCommand(cmd, term, currentDir, setDir) { + const command = cmd.trim(); + if (!command) return; + if (command === 'clear') { + term.clear(); + return; + } + if (command === 'ls') { + term.writeln(SECTIONS.join(' ')); + return; + } + if (command.startsWith('cd ')) { + const target = command.slice(3).trim().toLowerCase(); + if (SECTIONS.includes(target)) { + setDir(target); + scrollToSection(target); + term.writeln(`Changed directory to /${target}`); + } else { + term.writeln(`No such section: ${target}`); + } + return; + } + if (DATA[command.toLowerCase()]) { + term.writeln(DATA[command.toLowerCase()]); + } else { + term.writeln(`Command not found: ${command}`); + } + } + + function scrollToSection(section) { + const el = document.getElementById(section); + if (el) { + el.scrollIntoView({ behavior: 'smooth', block: 'start' }); + } + } + + return ( + <div style={{ width: '100%', maxWidth: 1000, margin: '2rem auto', background: '#161b22', borderRadius: 8, boxShadow: '0 2px 16px rgba(0,0,0,0.2)' }}> + <div ref={termRef} style={{ height: 500, width: '100%' }} /> + </div> + ); +}; + +export default Terminal;
\ No newline at end of file diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..6f725b5 --- /dev/null +++ b/src/index.css @@ -0,0 +1,683 @@ +@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@300;400;500;600;700&family=JetBrains+Mono:wght@100;200;300;400;500;600;700;800&display=swap'); + +/* Reset and base styles */ +html, body, #root { + height: 100%; + margin: 0; + padding: 0; + background: #fff; + color: #111; + font-family: 'Fira Mono', 'Consolas', 'Courier New', monospace; + font-size: 16px; + box-sizing: border-box; +} + +*, *::before, *::after { + box-sizing: inherit; +} + +h1, h2, h3, h4, h5, h6 { + font-family: inherit; + font-weight: bold; + text-transform: uppercase; + letter-spacing: 1px; + margin: 0 0 0.5em 0; +} + +button, input, select, textarea { + font-family: inherit; + font-size: 1em; + background: #fff; + color: #111; + border: 2px solid #111; + border-radius: 8px; + padding: 0.5em 1em; + outline: none; + transition: background 0.1s, color 0.1s; +} + +button { + cursor: pointer; + font-weight: bold; + letter-spacing: 1px; + background: #fff; + border: 2px solid #111; + border-radius: 8px; + margin: 0.25em; +} +button:active { + background: #111; + color: #fff; +} + +.card, .project-card, .modal { + border: 2.5px solid #111; + border-radius: 16px; + background: #fff; + padding: 1.5em 1em; + margin: 1em 0; + font-family: inherit; + box-shadow: none; +} + +input[type="text"], input[type="email"] { + border: 2px solid #111; + border-radius: 8px; + padding: 0.5em 1em; + background: #fff; + color: #111; +} + +/* Remove link underline, use black color */ +a { + color: #111; + text-decoration: none; + font-weight: bold; +} +a:hover { + text-decoration: underline; +} + +/* Responsive grid */ +@media (max-width: 600px) { + html, body { + font-size: 15px; + } + .card, .project-card, .modal { + padding: 1em 0.5em; + border-radius: 10px; + } + button { + padding: 0.5em 0.7em; + font-size: 0.95em; + } +} + +/* Matrix Rain Effect */ +.matrix-rain { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 1; + opacity: 0.1; +} + +.matrix-rain canvas { + width: 100%; + height: 100%; +} + +/* Main Content */ +#root { + position: relative; + z-index: 2; + min-height: 100vh; +} + +/* Smooth Scrolling Animations */ +.scroll-fade-in { + opacity: 0; + transform: translateY(30px); + transition: all 0.8s ease; +} + +.scroll-fade-in.visible { + opacity: 1; + transform: translateY(0); +} + +.scroll-slide-left { + opacity: 0; + transform: translateX(-50px); + transition: all 0.8s ease; +} + +.scroll-slide-left.visible { + opacity: 1; + transform: translateX(0); +} + +.scroll-slide-right { + opacity: 0; + transform: translateX(50px); + transition: all 0.8s ease; +} + +.scroll-slide-right.visible { + opacity: 1; + transform: translateX(0); +} + +.scroll-scale-in { + opacity: 0; + transform: scale(0.8); + transition: all 0.8s ease; +} + +.scroll-scale-in.visible { + opacity: 1; + transform: scale(1); +} + +/* Parallax Effects */ +.parallax-bg { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 120%; + background: linear-gradient(45deg, var(--terminal-green) 0%, transparent 50%, var(--cyan-blue) 100%); + opacity: 0.05; + transform: translateZ(-1px) scale(2); + z-index: -1; +} + +.parallax-slow { + transform: translateY(var(--parallax-y, 0px)); + transition: transform 0.1s ease-out; +} + +.parallax-medium { + transform: translateY(calc(var(--parallax-y, 0px) * 0.5)); + transition: transform 0.1s ease-out; +} + +.parallax-fast { + transform: translateY(calc(var(--parallax-y, 0px) * 0.25)); + transition: transform 0.1s ease-out; +} + +/* Floating Elements */ +.floating { + animation: float 6s ease-in-out infinite; +} + +@keyframes float { + 0%, 100% { transform: translateY(0px); } + 50% { transform: translateY(-20px); } +} + +.floating-delayed { + animation: float 6s ease-in-out infinite; + animation-delay: 2s; +} + +.floating-fast { + animation: float 4s ease-in-out infinite; +} + +/* Scroll Progress Bar */ +.scroll-progress { + position: fixed; + top: 0; + left: 0; + width: 0%; + height: 3px; + background: linear-gradient(90deg, var(--terminal-green), var(--cyan-blue)); + z-index: 1000; + transition: width 0.1s ease; +} + +/* Terminal Styling */ +.terminal { + background: var(--secondary-bg); + border: 1px solid var(--terminal-green); + border-radius: 8px; + padding: var(--spacing-md); + font-family: var(--font-mono); + font-size: var(--font-size-base); + color: var(--terminal-green); + box-shadow: 0 0 20px rgba(0, 255, 65, 0.3); + position: relative; + overflow: hidden; +} + +.terminal::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: linear-gradient(90deg, var(--terminal-green), var(--cyan-blue)); + animation: scan 2s linear infinite; +} + +@keyframes scan { + 0% { transform: translateX(-100%); } + 100% { transform: translateX(100%); } +} + +/* Terminal Prompt */ +.terminal-prompt { + color: var(--terminal-green); + font-weight: 600; +} + +.terminal-prompt::after { + content: '█'; + animation: blink 1s infinite; + color: var(--terminal-green); +} + +@keyframes blink { + 0%, 50% { opacity: 1; } + 51%, 100% { opacity: 0; } +} + +/* Typing Animation */ +.typewriter { + overflow: hidden; + border-right: 2px solid var(--terminal-green); + white-space: nowrap; + animation: typing 3.5s steps(40, end), blink-caret 0.75s step-end infinite; +} + +@keyframes typing { + from { width: 0; } + to { width: 100%; } +} + +@keyframes blink-caret { + from, to { border-color: transparent; } + 50% { border-color: var(--terminal-green); } +} + +/* Glitch Effect */ +.glitch { + position: relative; + animation: glitch 1s infinite; +} + +.glitch::before, +.glitch::after { + content: attr(data-text); + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.glitch::before { + animation: glitch-1 0.5s infinite; + color: var(--error-red); + z-index: -1; +} + +.glitch::after { + animation: glitch-2 0.5s infinite; + color: var(--cyan-blue); + z-index: -2; +} + +@keyframes glitch { + 0%, 100% { transform: translate(0); } + 20% { transform: translate(-2px, 2px); } + 40% { transform: translate(-2px, -2px); } + 60% { transform: translate(2px, 2px); } + 80% { transform: translate(2px, -2px); } +} + +@keyframes glitch-1 { + 0%, 100% { transform: translate(0); } + 20% { transform: translate(-2px, 2px); } + 40% { transform: translate(-2px, -2px); } + 60% { transform: translate(2px, 2px); } + 80% { transform: translate(2px, -2px); } +} + +@keyframes glitch-2 { + 0%, 100% { transform: translate(0); } + 20% { transform: translate(2px, -2px); } + 40% { transform: translate(2px, 2px); } + 60% { transform: translate(-2px, -2px); } + 80% { transform: translate(-2px, 2px); } +} + +/* Neon Glow Effects */ +.neon-glow { + text-shadow: + 0 0 5px currentColor, + 0 0 10px currentColor, + 0 0 15px currentColor, + 0 0 20px currentColor; +} + +.neon-glow-green { + color: var(--terminal-green); + text-shadow: + 0 0 5px var(--terminal-green), + 0 0 10px var(--terminal-green), + 0 0 15px var(--terminal-green), + 0 0 20px var(--terminal-green); +} + +.neon-glow-cyan { + color: var(--cyan-blue); + text-shadow: + 0 0 5px var(--cyan-blue), + 0 0 10px var(--cyan-blue), + 0 0 15px var(--cyan-blue), + 0 0 20px var(--cyan-blue); +} + +/* Button Styles */ +.btn { + background: transparent; + border: 2px solid var(--terminal-green); + color: var(--terminal-green); + padding: var(--spacing-sm) var(--spacing-lg); + font-family: var(--font-mono); + font-size: var(--font-size-base); + cursor: pointer; + transition: all var(--transition-normal); + position: relative; + overflow: hidden; +} + +.btn::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(0, 255, 65, 0.2), transparent); + transition: left var(--transition-slow); +} + +.btn:hover::before { + left: 100%; +} + +.btn:hover { + background: var(--terminal-green); + color: var(--primary-bg); + box-shadow: 0 0 20px rgba(0, 255, 65, 0.5); +} + +/* Navigation */ +.nav { + background: transparent; + backdrop-filter: none; + position: sticky; + top: 0; + z-index: 100; + margin-bottom: 2rem; +} + +.nav-link { + color: #111; + text-decoration: none; + padding: var(--spacing-sm) var(--spacing-md); + transition: all var(--transition-normal); + position: relative; + font-weight: bold; + text-shadow: 0 1px 4px rgba(0,0,0,0.08); + flex: 1; + text-align: center; +} + +.nav-link::after { + content: ''; + position: absolute; + bottom: 0; + left: 50%; + width: 0; + height: 2px; + background: var(--terminal-green); + transition: all var(--transition-normal); + transform: translateX(-50%); +} + +.nav-link:hover::after { + width: 100%; +} + +.nav-link:hover { + color: var(--terminal-green); +} + +/* Section Styles */ +.section { + padding: var(--spacing-2xl) 0; + position: relative; +} + +.section-title { + font-size: var(--font-size-3xl); + color: var(--terminal-green); + margin-bottom: var(--spacing-xl); + text-align: center; + font-weight: 600; +} + +/* Card Styles */ +.card { + background: var(--secondary-bg); + border: 1px solid var(--light-gray); + border-radius: 8px; + padding: var(--spacing-lg); + transition: all var(--transition-normal); + position: relative; + overflow: hidden; +} + +.card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: linear-gradient(90deg, var(--terminal-green), var(--cyan-blue)); + transform: scaleX(0); + transition: transform var(--transition-normal); +} + +.card:hover::before { + transform: scaleX(1); +} + +.card:hover { + border-color: var(--terminal-green); + box-shadow: 0 0 20px rgba(0, 255, 65, 0.2); + transform: translateY(-2px); +} + +/* Interactive Scroll Elements */ +.scroll-trigger { + opacity: 0; + transform: translateY(50px); + transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1); +} + +.scroll-trigger.triggered { + opacity: 1; + transform: translateY(0); +} + +/* Particle System */ +.particles { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 1; +} + +.particle { + position: absolute; + width: 2px; + height: 2px; + background: var(--terminal-green); + border-radius: 50%; + animation: particle-float 8s linear infinite; +} + +@keyframes particle-float { + 0% { + transform: translateY(100vh) translateX(0); + opacity: 0; + } + 10% { + opacity: 1; + } + 90% { + opacity: 1; + } + 100% { + transform: translateY(-100px) translateX(100px); + opacity: 0; + } +} + +/* Responsive Design */ +@media (max-width: 768px) { + .section { + padding: var(--spacing-xl) 0; + } + + .section-title { + font-size: var(--font-size-2xl); +} + + .terminal { + font-size: var(--font-size-small); + padding: var(--spacing-sm); + } +} + +/* Scrollbar Styling */ +::-webkit-scrollbar { + width: 8px; +} + +::-webkit-scrollbar-track { + background: var(--secondary-bg); +} + +::-webkit-scrollbar-thumb { + background: var(--terminal-green); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--matrix-green); +} + +/* Selection Styling */ +::selection { + background: var(--terminal-green); + color: var(--primary-bg); +} + +/* Focus Styles */ +:focus { + outline: 2px solid var(--terminal-green); + outline-offset: 2px; +} + +/* Loading Animation */ +.loading { + display: inline-block; + width: 20px; + height: 20px; + border: 3px solid var(--light-gray); + border-radius: 50%; + border-top-color: var(--terminal-green); + animation: spin 1s ease-in-out infinite; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +/* ASCII Art */ +.ascii-art { + font-family: var(--font-mono); + white-space: pre; + color: var(--terminal-green); + text-align: center; + line-height: 1.2; +} + +/* Command Palette */ +.command-palette { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: var(--secondary-bg); + border: 1px solid var(--terminal-green); + border-radius: 8px; + padding: var(--spacing-lg); + z-index: 1000; + min-width: 400px; + box-shadow: 0 0 30px rgba(0, 255, 65, 0.3); +} + +.command-palette input { + width: 100%; + background: transparent; + border: none; + color: var(--terminal-green); + font-family: var(--font-mono); + font-size: var(--font-size-base); + outline: none; + } + +.command-palette input::placeholder { + color: var(--light-gray); +} + +/* Utility Classes */ +.text-green { color: var(--terminal-green); } +.text-cyan { color: var(--cyan-blue); } +.text-red { color: var(--error-red); } +.text-orange { color: var(--warning-orange); } +.text-white { color: var(--bright-white); } + +.bg-dark { background: var(--primary-bg); } +.bg-secondary { background: var(--secondary-bg); } +.bg-gray { background: var(--dark-gray); } + +.border-green { border-color: var(--terminal-green); } +.border-cyan { border-color: var(--cyan-blue); } + +.hidden { display: none; } +.visible { display: block; } + +.flex { display: flex; } +.flex-col { flex-direction: column; } +.items-center { align-items: center; } +.justify-center { justify-content: center; } +.justify-between { justify-content: space-between; } + +.w-full { width: 100%; } +.h-full { height: 100%; } + +.text-center { text-align: center; } +.text-left { text-align: left; } +.text-right { text-align: right; } + +.mb-1 { margin-bottom: var(--spacing-xs); } +.mb-2 { margin-bottom: var(--spacing-sm); } +.mb-4 { margin-bottom: var(--spacing-md); } +.mb-8 { margin-bottom: var(--spacing-lg); } + +.mt-1 { margin-top: var(--spacing-xs); } +.mt-2 { margin-top: var(--spacing-sm); } +.mt-4 { margin-top: var(--spacing-md); } +.mt-8 { margin-top: var(--spacing-lg); } + +.p-1 { padding: var(--spacing-xs); } +.p-2 { padding: var(--spacing-sm); } +.p-4 { padding: var(--spacing-md); } +.p-8 { padding: var(--spacing-lg); } diff --git a/src/main.jsx b/src/main.jsx new file mode 100644 index 0000000..b9a1a6d --- /dev/null +++ b/src/main.jsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + <StrictMode> + <App /> + </StrictMode>, +) diff --git a/src/pages/About.jsx b/src/pages/About.jsx new file mode 100644 index 0000000..c3b4872 --- /dev/null +++ b/src/pages/About.jsx @@ -0,0 +1,302 @@ +import React from 'react'; +import { motion } from 'framer-motion'; +import { Heart, Shield, Users, Globe, Code, BookOpen } from 'lucide-react'; + +const About = () => { + const values = [ + { + icon: Heart, + title: 'Open Source Advocacy', + description: 'We believe in the power of open source software and its ability to democratize technology.', + color: 'text-green' + }, + { + icon: Shield, + title: 'Privacy & Security', + description: 'Promoting digital privacy and security through open source solutions and education.', + color: 'text-cyan' + }, + { + icon: Users, + title: 'Community Building', + description: 'Creating a supportive environment where students can learn, grow, and collaborate.', + color: 'text-green' + }, + { + icon: Globe, + title: 'Global Impact', + description: 'Contributing to the global open source ecosystem and making technology accessible to all.', + color: 'text-cyan' + }, + { + icon: Code, + title: 'Hands-on Learning', + description: 'Providing practical experience through real-world projects and coding challenges.', + color: 'text-green' + }, + { + icon: BookOpen, + title: 'Knowledge Sharing', + description: 'Fostering a culture of learning and sharing knowledge with the broader community.', + color: 'text-cyan' + } + ]; + + const timeline = [ + { + year: '2020', + title: 'Club Founded', + description: 'FOSSEE Club was established with the vision of promoting open source software in education.' + }, + { + year: '2021', + title: 'First Workshop', + description: 'Conducted our first Linux workshop, introducing students to open source operating systems.' + }, + { + year: '2022', + title: 'Project Contributions', + description: 'Started contributing to open source projects and organizing hackathons.' + }, + { + year: '2023', + title: 'Community Growth', + description: 'Expanded our community and established partnerships with other tech clubs.' + }, + { + year: '2024', + title: 'Innovation Hub', + description: 'Became a hub for innovation, hosting regular events and mentoring programs.' + } + ]; + + return ( + <div className="min-h-screen"> + {/* Hero Section */} + <section className="section relative"> + <div className="parallax-bg"></div> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 50 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8 }} + className="text-center mb-16 scroll-fade-in" + > + <h1 className="text-4xl md:text-6xl font-bold mb-6"> + About <span className="text-green neon-glow-green floating">FOSSEE</span> + </h1> + <p className="text-xl text-gray max-w-4xl mx-auto"> + We are a community of passionate students dedicated to promoting Free and Open Source Software (FOSS) + in education. Our mission is to empower students with the knowledge and skills needed to thrive + in the digital age through open source technology. + </p> + </motion.div> + </div> + </section> + + {/* Mission Section */} + <section className="section bg-secondary relative"> + <div className="parallax-bg"></div> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.2 }} + className="max-w-4xl mx-auto scroll-trigger" + > + <h2 className="section-title">Our Mission</h2> + <div className="terminal floating mb-8"> + <div className="terminal-prompt">root@fossee:~$ cat mission.txt</div> + <div className="text-white mt-2 whitespace-pre-wrap"> +{`FOSSEE Club Mission Statement +================================ + +We strive to: + +1. EDUCATE students about the importance and benefits of open source software +2. EMPOWER individuals with practical skills in Linux, programming, and open source tools +3. ENCOURAGE active participation in the global open source community +4. ENHANCE learning through hands-on projects and real-world applications +5. ESTABLISH a supportive network of like-minded developers and enthusiasts + +Our vision is to create a world where technology is accessible, +transparent, and beneficial to all through the power of open source.`} + </div> + </div> + </motion.div> + </div> + </section> + + {/* Values Section */} + <section className="section relative"> + <div className="parallax-bg"></div> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.4 }} + className="scroll-trigger" + > + <h2 className="section-title">Our Values</h2> + <div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8"> + {values.map((value, index) => ( + <motion.div + key={index} + initial={{ opacity: 0, y: 20 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.5, delay: 0.1 * index }} + whileHover={{ y: -5 }} + className={`card text-center scroll-scale-in`} + > + <value.icon className={`w-12 h-12 mx-auto mb-4 ${value.color} floating`} /> + <h3 className="text-xl font-bold mb-2 text-green">{value.title}</h3> + <p className="text-gray">{value.description}</p> + </motion.div> + ))} + </div> + </motion.div> + </div> + </section> + + {/* FOSS Philosophy Section */} + <section className="section bg-secondary relative"> + <div className="parallax-bg"></div> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.6 }} + className="max-w-4xl mx-auto scroll-trigger" + > + <h2 className="section-title">FOSS Philosophy</h2> + <div className="grid md:grid-cols-2 gap-8"> + <div className="card scroll-slide-left"> + <h3 className="text-xl font-bold mb-4 text-green">The Four Freedoms</h3> + <div className="space-y-3"> + <div className="flex items-start space-x-3"> + <span className="text-green font-bold">0.</span> + <p>The freedom to run the program as you wish, for any purpose.</p> + </div> + <div className="flex items-start space-x-3"> + <span className="text-green font-bold">1.</span> + <p>The freedom to study how the program works, and change it to make it do what you wish.</p> + </div> + <div className="flex items-start space-x-3"> + <span className="text-green font-bold">2.</span> + <p>The freedom to redistribute copies so you can help others.</p> + </div> + <div className="flex items-start space-x-3"> + <span className="text-green font-bold">3.</span> + <p>The freedom to distribute copies of your modified versions to others.</p> + </div> + </div> + </div> + + <div className="card scroll-slide-right"> + <h3 className="text-xl font-bold mb-4 text-cyan">Why Open Source?</h3> + <ul className="space-y-3 text-gray"> + <li className="flex items-start space-x-2"> + <span className="text-green">▶</span> + <span>Transparency and trust in software</span> + </li> + <li className="flex items-start space-x-2"> + <span className="text-green">▶</span> + <span>Community-driven development</span> + </li> + <li className="flex items-start space-x-2"> + <span className="text-green">▶</span> + <span>Cost-effective solutions</span> + </li> + <li className="flex items-start space-x-2"> + <span className="text-green">▶</span> + <span>Freedom from vendor lock-in</span> + </li> + <li className="flex items-start space-x-2"> + <span className="text-green">▶</span> + <span>Educational opportunities</span> + </li> + <li className="flex items-start space-x-2"> + <span className="text-green">▶</span> + <span>Innovation through collaboration</span> + </li> + </ul> + </div> + </div> + </motion.div> + </div> + </section> + + {/* Timeline Section */} + <section className="section relative"> + <div className="parallax-bg"></div> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.8 }} + className="scroll-trigger" + > + <h2 className="section-title">Our Journey</h2> + <div className="max-w-4xl mx-auto"> + <div className="relative"> + {/* Timeline Line */} + <div className="absolute left-8 top-0 bottom-0 w-0.5 bg-green"></div> + + {timeline.map((item, index) => ( + <motion.div + key={index} + initial={{ opacity: 0, x: -50 }} + animate={{ opacity: 1, x: 0 }} + transition={{ duration: 0.5, delay: 0.1 * index }} + className="relative flex items-start mb-8 scroll-fade-in" + > + {/* Timeline Dot */} + <div className="absolute left-6 w-4 h-4 bg-green rounded-full border-4 border-secondary floating"></div> + + {/* Content */} + <div className="ml-16 card flex-1"> + <div className="flex items-center justify-between mb-2"> + <span className="text-2xl font-bold text-green">{item.year}</span> + <span className="text-sm text-gray">FOSSEE Club</span> + </div> + <h3 className="text-lg font-bold mb-2 text-white">{item.title}</h3> + <p className="text-gray">{item.description}</p> + </div> + </motion.div> + ))} + </div> + </div> + </motion.div> + </div> + </section> + + {/* Join Us Section */} + <section className="section bg-secondary relative"> + <div className="parallax-bg"></div> + <div className="container mx-auto px-4 text-center"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 1 }} + className="scroll-trigger" + > + <h2 className="text-3xl font-bold mb-4 text-green">Join Our Community</h2> + <p className="text-xl text-gray mb-8 max-w-2xl mx-auto"> + Whether you're a beginner or an experienced developer, there's a place for you in our community. + Together, we can build a better future through open source. + </p> + <motion.button + whileHover={{ scale: 1.05 }} + whileTap={{ scale: 0.95 }} + className="btn text-lg px-8 py-4 floating" + > + Become a Member + </motion.button> + </motion.div> + </div> + </section> + </div> + ); +}; + +export default About;
\ No newline at end of file diff --git a/src/pages/Contact.jsx b/src/pages/Contact.jsx new file mode 100644 index 0000000..6aca659 --- /dev/null +++ b/src/pages/Contact.jsx @@ -0,0 +1,336 @@ +import React, { useState } from 'react'; +import { motion } from 'framer-motion'; +import { Mail, MapPin, Phone, Send, Github, Linkedin, MessageSquare } from 'lucide-react'; + +const Contact = () => { + const [formData, setFormData] = useState({ + name: '', + email: '', + subject: '', + message: '' + }); + const [isSubmitting, setIsSubmitting] = useState(false); + const [submitStatus, setSubmitStatus] = useState(null); + + const handleInputChange = (e) => { + const { name, value } = e.target; + setFormData(prev => ({ + ...prev, + [name]: value + })); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + setIsSubmitting(true); + + // Simulate form submission + setTimeout(() => { + setIsSubmitting(false); + setSubmitStatus('success'); + setFormData({ name: '', email: '', subject: '', message: '' }); + + setTimeout(() => setSubmitStatus(null), 3000); + }, 2000); + }; + + const contactInfo = [ + { + icon: Mail, + title: 'Email', + value: 'contact@fossee-club.org', + link: 'mailto:contact@fossee-club.org' + }, + { + icon: MapPin, + title: 'Location', + value: 'Computer Science Department\nUniversity Campus', + link: null + }, + { + icon: Phone, + title: 'Phone', + value: '+1 (555) 123-4567', + link: 'tel:+15551234567' + } + ]; + + const socialLinks = [ + { + icon: Github, + title: 'GitHub', + url: 'https://github.com/fossee-club', + color: 'hover:text-green' + }, + { + icon: Linkedin, + title: 'LinkedIn', + url: 'https://linkedin.com/company/fossee-club', + color: 'hover:text-cyan' + }, + { + icon: MessageSquare, + title: 'Discord', + url: 'https://discord.gg/fossee-club', + color: 'hover:text-green' + } + ]; + + return ( + <div className="min-h-screen"> + {/* Hero Section */} + <section className="section"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 50 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8 }} + className="text-center mb-16" + > + <h1 className="text-4xl md:text-6xl font-bold mb-6"> + Get in <span className="text-green neon-glow-green">Touch</span> + </h1> + <p className="text-xl text-gray max-w-3xl mx-auto"> + Have questions about our club, events, or projects? We'd love to hear from you! + Reach out to us through any of the channels below. + </p> + </motion.div> + </div> + </section> + + {/* Contact Form Section */} + <section className="section bg-secondary"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.2 }} + className="max-w-4xl mx-auto" + > + <h2 className="section-title">Send us a Message</h2> + <div className="grid md:grid-cols-2 gap-8"> + {/* Contact Form */} + <div className="card"> + <form onSubmit={handleSubmit} className="space-y-4"> + <div> + <label className="block text-sm font-medium text-green mb-2"> + Name + </label> + <input + type="text" + name="name" + value={formData.name} + onChange={handleInputChange} + required + className="w-full bg-transparent border border-light-gray rounded px-3 py-2 text-white focus:border-green focus:outline-none transition-colors" + placeholder="Your name" + /> + </div> + + <div> + <label className="block text-sm font-medium text-green mb-2"> + Email + </label> + <input + type="email" + name="email" + value={formData.email} + onChange={handleInputChange} + required + className="w-full bg-transparent border border-light-gray rounded px-3 py-2 text-white focus:border-green focus:outline-none transition-colors" + placeholder="your.email@example.com" + /> + </div> + + <div> + <label className="block text-sm font-medium text-green mb-2"> + Subject + </label> + <input + type="text" + name="subject" + value={formData.subject} + onChange={handleInputChange} + required + className="w-full bg-transparent border border-light-gray rounded px-3 py-2 text-white focus:border-green focus:outline-none transition-colors" + placeholder="What's this about?" + /> + </div> + + <div> + <label className="block text-sm font-medium text-green mb-2"> + Message + </label> + <textarea + name="message" + value={formData.message} + onChange={handleInputChange} + required + rows={5} + className="w-full bg-transparent border border-light-gray rounded px-3 py-2 text-white focus:border-green focus:outline-none transition-colors resize-none" + placeholder="Tell us more..." + /> + </div> + + <motion.button + type="submit" + disabled={isSubmitting} + whileHover={{ scale: 1.02 }} + whileTap={{ scale: 0.98 }} + className="btn w-full flex items-center justify-center space-x-2" + > + {isSubmitting ? ( + <> + <div className="loading w-4 h-4"></div> + <span>Sending...</span> + </> + ) : ( + <> + <Send className="w-4 h-4" /> + <span>Send Message</span> + </> + )} + </motion.button> + + {submitStatus === 'success' && ( + <motion.div + initial={{ opacity: 0, y: 10 }} + animate={{ opacity: 1, y: 0 }} + className="text-green text-center py-2" + > + ✓ Message sent successfully! + </motion.div> + )} + </form> + </div> + + {/* Contact Information */} + <div className="space-y-6"> + <div> + <h3 className="text-xl font-bold mb-4 text-green">Contact Information</h3> + <div className="space-y-4"> + {contactInfo.map((info, index) => ( + <motion.div + key={index} + initial={{ opacity: 0, x: 20 }} + animate={{ opacity: 1, x: 0 }} + transition={{ duration: 0.5, delay: 0.1 * index }} + className="flex items-start space-x-3" + > + <info.icon className="w-5 h-5 text-green mt-1" /> + <div> + <div className="font-medium text-white">{info.title}</div> + {info.link ? ( + <a + href={info.link} + className="text-gray hover:text-green transition-colors" + > + {info.value} + </a> + ) : ( + <div className="text-gray whitespace-pre-line">{info.value}</div> + )} + </div> + </motion.div> + ))} + </div> + </div> + + <div> + <h3 className="text-xl font-bold mb-4 text-green">Follow Us</h3> + <div className="flex space-x-4"> + {socialLinks.map((social, index) => ( + <motion.a + key={index} + href={social.url} + target="_blank" + rel="noopener noreferrer" + initial={{ opacity: 0, scale: 0.8 }} + animate={{ opacity: 1, scale: 1 }} + transition={{ duration: 0.5, delay: 0.2 + 0.1 * index }} + whileHover={{ scale: 1.1 }} + whileTap={{ scale: 0.9 }} + className={`text-gray ${social.color} transition-colors`} + title={social.title} + > + <social.icon className="w-6 h-6" /> + </motion.a> + ))} + </div> + </div> + </div> + </div> + </motion.div> + </div> + </section> + + {/* FAQ Section */} + <section className="section"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.4 }} + > + <h2 className="section-title">Frequently Asked Questions</h2> + <div className="max-w-3xl mx-auto space-y-4"> + <motion.div + initial={{ opacity: 0, y: 20 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.5, delay: 0.1 }} + className="card" + > + <h3 className="text-lg font-bold mb-2 text-green">How do I join the FOSSEE club?</h3> + <p className="text-gray"> + Simply attend one of our events or workshops! We welcome students of all skill levels. + You can also reach out to us through the contact form above. + </p> + </motion.div> + + <motion.div + initial={{ opacity: 0, y: 20 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.5, delay: 0.2 }} + className="card" + > + <h3 className="text-lg font-bold mb-2 text-green">Do I need prior experience with Linux?</h3> + <p className="text-gray"> + Not at all! We have workshops and resources for complete beginners. Our community is + built around learning and helping each other grow. + </p> + </motion.div> + + <motion.div + initial={{ opacity: 0, y: 20 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.5, delay: 0.3 }} + className="card" + > + <h3 className="text-lg font-bold mb-2 text-green">Can I contribute to open source projects?</h3> + <p className="text-gray"> + Absolutely! We help students find beginner-friendly projects and guide them through + their first contributions. Check out our Projects page for opportunities. + </p> + </motion.div> + + <motion.div + initial={{ opacity: 0, y: 20 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.5, delay: 0.4 }} + className="card" + > + <h3 className="text-lg font-bold mb-2 text-green">What events do you organize?</h3> + <p className="text-gray"> + We host workshops, hackathons, coding competitions, and networking events. + Check our Events page for the latest schedule and upcoming activities. + </p> + </motion.div> + </div> + </motion.div> + </div> + </section> + </div> + ); +}; + +export default Contact;
\ No newline at end of file diff --git a/src/pages/Events.jsx b/src/pages/Events.jsx new file mode 100644 index 0000000..c24dc19 --- /dev/null +++ b/src/pages/Events.jsx @@ -0,0 +1,325 @@ +import React, { useState } from 'react'; +import { motion } from 'framer-motion'; +import { Calendar, Clock, MapPin, Users, Code, BookOpen, Trophy, Zap } from 'lucide-react'; + +const Events = () => { + const [activeFilter, setActiveFilter] = useState('all'); + + const events = [ + { + id: 1, + title: 'Linux Fundamentals Workshop', + type: 'workshop', + date: '2024-03-15', + time: '10:00 AM - 2:00 PM', + location: 'Computer Lab 101', + capacity: 30, + registered: 25, + description: 'Learn the basics of Linux command line, file system, and basic administration.', + tags: ['Linux', 'Beginner', 'Hands-on'], + icon: BookOpen + }, + { + id: 2, + title: 'Open Source Hackathon 2024', + type: 'hackathon', + date: '2024-04-01', + time: '48 Hours', + location: 'Innovation Center', + capacity: 100, + registered: 85, + description: 'Build innovative solutions using open source technologies. Prizes worth $5000.', + tags: ['Hackathon', 'Advanced', 'Competition'], + icon: Code + }, + { + id: 3, + title: 'Git & GitHub Masterclass', + type: 'workshop', + date: '2024-03-22', + time: '2:00 PM - 5:00 PM', + location: 'Online', + capacity: 50, + registered: 42, + description: 'Master version control with Git and collaboration on GitHub.', + tags: ['Git', 'GitHub', 'Intermediate'], + icon: BookOpen + }, + { + id: 4, + title: 'Coding Competition: Algorithm Challenge', + type: 'competition', + date: '2024-03-30', + time: '3:00 PM - 6:00 PM', + location: 'Main Auditorium', + capacity: 60, + registered: 58, + description: 'Solve algorithmic problems and compete for the top spot.', + tags: ['Algorithms', 'Competition', 'Advanced'], + icon: Trophy + }, + { + id: 5, + title: 'Web Development Bootcamp', + type: 'workshop', + date: '2024-04-08', + time: '10:00 AM - 4:00 PM', + location: 'Computer Lab 102', + capacity: 40, + registered: 35, + description: 'Build modern web applications using React, Node.js, and open source tools.', + tags: ['Web Dev', 'React', 'Intermediate'], + icon: BookOpen + }, + { + id: 6, + title: 'Lightning Talks: Open Source Projects', + type: 'event', + date: '2024-04-15', + time: '6:00 PM - 8:00 PM', + location: 'Conference Room A', + capacity: 80, + registered: 65, + description: 'Quick presentations on interesting open source projects and contributions.', + tags: ['Talks', 'Projects', 'All Levels'], + icon: Zap + } + ]; + + const filters = [ + { id: 'all', label: 'All Events', icon: Calendar }, + { id: 'workshop', label: 'Workshops', icon: BookOpen }, + { id: 'hackathon', label: 'Hackathons', icon: Code }, + { id: 'competition', label: 'Competitions', icon: Trophy }, + { id: 'event', label: 'Events', icon: Zap } + ]; + + const filteredEvents = events.filter(event => + activeFilter === 'all' || event.type === activeFilter + ); + + const getTypeColor = (type) => { + switch (type) { + case 'workshop': return 'text-green'; + case 'hackathon': return 'text-cyan'; + case 'competition': return 'text-orange'; + case 'event': return 'text-green'; + default: return 'text-white'; + } + }; + + const getProgressPercentage = (registered, capacity) => { + return (registered / capacity) * 100; + }; + + return ( + <div className="min-h-screen"> + {/* Hero Section */} + <section className="section"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 50 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8 }} + className="text-center mb-16" + > + <h1 className="text-4xl md:text-6xl font-bold mb-6"> + <span className="text-green neon-glow-green">Events</span> & Activities + </h1> + <p className="text-xl text-gray max-w-3xl mx-auto"> + Join our exciting events, workshops, and competitions. Learn, compete, and grow with the FOSSEE community. + </p> + </motion.div> + </div> + </section> + + {/* Filters Section */} + <section className="section bg-secondary"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.2 }} + > + <h2 className="section-title">Browse Events</h2> + <div className="flex flex-wrap justify-center gap-4 mb-8"> + {filters.map((filter) => ( + <motion.button + key={filter.id} + whileHover={{ scale: 1.05 }} + whileTap={{ scale: 0.95 }} + onClick={() => setActiveFilter(filter.id)} + className={`flex items-center space-x-2 px-4 py-2 rounded border transition-colors ${ + activeFilter === filter.id + ? 'border-green text-green bg-green bg-opacity-10' + : 'border-light-gray text-gray hover:border-green hover:text-green' + }`} + > + <filter.icon className="w-4 h-4" /> + <span>{filter.label}</span> + </motion.button> + ))} + </div> + </motion.div> + </div> + </section> + + {/* Events Grid */} + <section className="section"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.4 }} + className="grid md:grid-cols-2 lg:grid-cols-3 gap-8" + > + {filteredEvents.map((event, index) => ( + <motion.div + key={event.id} + initial={{ opacity: 0, y: 20 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.5, delay: 0.1 * index }} + whileHover={{ y: -5 }} + className="card" + > + <div className="flex items-start justify-between mb-4"> + <event.icon className={`w-8 h-8 ${getTypeColor(event.type)}`} /> + <span className={`text-sm px-2 py-1 rounded ${getTypeColor(event.type)} bg-opacity-10`}> + {event.type.toUpperCase()} + </span> + </div> + + <h3 className="text-xl font-bold mb-2 text-white">{event.title}</h3> + <p className="text-gray mb-4">{event.description}</p> + + <div className="space-y-2 mb-4"> + <div className="flex items-center space-x-2 text-sm"> + <Calendar className="w-4 h-4 text-green" /> + <span className="text-gray">{event.date}</span> + </div> + <div className="flex items-center space-x-2 text-sm"> + <Clock className="w-4 h-4 text-cyan" /> + <span className="text-gray">{event.time}</span> + </div> + <div className="flex items-center space-x-2 text-sm"> + <MapPin className="w-4 h-4 text-green" /> + <span className="text-gray">{event.location}</span> + </div> + <div className="flex items-center space-x-2 text-sm"> + <Users className="w-4 h-4 text-cyan" /> + <span className="text-gray">{event.registered}/{event.capacity} registered</span> + </div> + </div> + + {/* Progress Bar */} + <div className="mb-4"> + <div className="flex justify-between text-xs mb-1"> + <span className="text-gray">Registration</span> + <span className="text-green">{Math.round(getProgressPercentage(event.registered, event.capacity))}%</span> + </div> + <div className="w-full bg-light-gray rounded-full h-2"> + <div + className="bg-green h-2 rounded-full transition-all duration-300" + style={{ width: `${getProgressPercentage(event.registered, event.capacity)}%` }} + ></div> + </div> + </div> + + {/* Tags */} + <div className="flex flex-wrap gap-2 mb-4"> + {event.tags.map((tag, tagIndex) => ( + <span + key={tagIndex} + className="text-xs px-2 py-1 bg-green bg-opacity-10 text-green rounded" + > + {tag} + </span> + ))} + </div> + + <motion.button + whileHover={{ scale: 1.02 }} + whileTap={{ scale: 0.98 }} + className="btn w-full" + disabled={event.registered >= event.capacity} + > + {event.registered >= event.capacity ? 'Fully Booked' : 'Register Now'} + </motion.button> + </motion.div> + ))} + </motion.div> + + {filteredEvents.length === 0 && ( + <motion.div + initial={{ opacity: 0 }} + animate={{ opacity: 1 }} + className="text-center py-16" + > + <Calendar className="w-16 h-16 text-gray mx-auto mb-4" /> + <h3 className="text-xl font-bold mb-2 text-gray">No Events Found</h3> + <p className="text-gray">Check back later for new events or try a different filter.</p> + </motion.div> + )} + </div> + </section> + + {/* Upcoming Highlights */} + <section className="section bg-secondary"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.6 }} + > + <h2 className="section-title">Upcoming Highlights</h2> + <div className="grid md:grid-cols-2 gap-8"> + <div className="card"> + <div className="flex items-center space-x-4 mb-4"> + <Trophy className="w-12 h-12 text-orange" /> + <div> + <h3 className="text-xl font-bold text-white">Annual Hackathon</h3> + <p className="text-gray">April 1-3, 2024</p> + </div> + </div> + <p className="text-gray mb-4"> + Our biggest event of the year! 48 hours of coding, innovation, and collaboration. + Build something amazing with open source technologies. + </p> + <motion.button + whileHover={{ scale: 1.05 }} + whileTap={{ scale: 0.95 }} + className="btn" + > + Learn More + </motion.button> + </div> + + <div className="card"> + <div className="flex items-center space-x-4 mb-4"> + <BookOpen className="w-12 h-12 text-green" /> + <div> + <h3 className="text-xl font-bold text-white">Linux Workshop Series</h3> + <p className="text-gray">Every Saturday</p> + </div> + </div> + <p className="text-gray mb-4"> + Weekly hands-on workshops covering Linux administration, shell scripting, + and system administration. Perfect for beginners and intermediate users. + </p> + <motion.button + whileHover={{ scale: 1.05 }} + whileTap={{ scale: 0.95 }} + className="btn" + > + View Schedule + </motion.button> + </div> + </div> + </motion.div> + </div> + </section> + </div> + ); +}; + +export default Events;
\ No newline at end of file diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx new file mode 100644 index 0000000..51acb03 --- /dev/null +++ b/src/pages/Home.jsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { motion } from 'framer-motion'; +import { TypeAnimation } from 'react-type-animation'; +import Terminal from '../components/Terminal'; + +const Home = () => { + const asciiArt = ` + ███████╗ ██████╗ ███████╗███████╗ ███████╗██╗ ██╗███████╗ █████╗ ████████╗ + ██╔════╝██╔═══██╗██╔════╝██╔════╝ ██╔════╝██║ ██║██╔════╝██╔══██╗╚══██╔══╝ + █████╗ ██║ ██║███████╗███████╗ ██║ ██║ ██║███████╗███████║ ██║ + ██╔══╝ ██║ ██║╚════██║╚════██║ ██║ ██║ ██║╚════██║██╔══██║ ██║ + ██║ ╚██████╔╝███████║███████║ ╚██████╗╚██████╔╝███████║██║ ██║ ██║ + ╚═╝ ╚═════╝ ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ + `; + + return ( + <div className="min-h-screen"> + {/* Hero Section */} + <section className="section relative" id="home"> + <div className="parallax-bg"></div> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 50 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8 }} + className="text-center mb-16" + > + <div className="ascii-art mb-8 floating"> + {asciiArt} + </div> + + <h1 className="text-4xl md:text-6xl font-bold mb-6 scroll-fade-in"> + <span className="text-green neon-glow-green">FOSS CUSAT</span> + <br /> + <TypeAnimation + sequence={[ + 'Free and Open Source Software for Education', + 2000, + 'Empowering Students Through Open Source', + 2000, + 'Building the Future of Technology', + 2000, + ]} + wrapper="span" + speed={50} + className="text-cyan neon-glow-cyan" + repeat={Infinity} + /> + </h1> + </motion.div> + </div> + </section> + <Terminal /> + </div> + ); +}; + +export default Home;
\ No newline at end of file diff --git a/src/pages/Projects.jsx b/src/pages/Projects.jsx new file mode 100644 index 0000000..6aeabe3 --- /dev/null +++ b/src/pages/Projects.jsx @@ -0,0 +1,309 @@ +import React, { useState } from 'react'; +import { motion } from 'framer-motion'; +import { Code, Github, ExternalLink, Star, GitBranch, Users, Calendar } from 'lucide-react'; + +const Projects = () => { + const [activeFilter, setActiveFilter] = useState('all'); + + const projects = [ + { + id: 1, + title: 'FOSSEE Website', + description: 'Modern website for the FOSSEE club built with React and Vite. Features terminal interface and dark theme.', + category: 'web', + tech: ['React', 'Vite', 'CSS3', 'JavaScript'], + github: 'https://github.com/fossee-club/website', + live: 'https://fossee-club.org', + stars: 45, + forks: 12, + contributors: 8, + lastUpdated: '2024-03-10', + status: 'active' + }, + { + id: 2, + title: 'Linux Command Trainer', + description: 'Interactive web application to learn Linux commands through hands-on exercises and challenges.', + category: 'education', + tech: ['Python', 'Flask', 'JavaScript', 'SQLite'], + github: 'https://github.com/fossee-club/linux-trainer', + live: 'https://linux-trainer.fossee.org', + stars: 23, + forks: 5, + contributors: 4, + lastUpdated: '2024-03-08', + status: 'active' + }, + { + id: 3, + title: 'Open Source Project Finder', + description: 'Tool to help students find beginner-friendly open source projects to contribute to.', + category: 'tool', + tech: ['Node.js', 'Express', 'MongoDB', 'React'], + github: 'https://github.com/fossee-club/project-finder', + live: 'https://project-finder.fossee.org', + stars: 67, + forks: 15, + contributors: 12, + lastUpdated: '2024-03-05', + status: 'active' + }, + { + id: 4, + title: 'FOSSEE Mobile App', + description: 'Mobile application for FOSSEE club members to stay updated with events and projects.', + category: 'mobile', + tech: ['React Native', 'Firebase', 'Redux', 'TypeScript'], + github: 'https://github.com/fossee-club/mobile-app', + live: null, + stars: 34, + forks: 8, + contributors: 6, + lastUpdated: '2024-03-01', + status: 'development' + }, + { + id: 5, + title: 'Code Review Bot', + description: 'Automated code review bot for GitHub repositories with focus on open source best practices.', + category: 'tool', + tech: ['Python', 'GitHub API', 'Docker', 'PostgreSQL'], + github: 'https://github.com/fossee-club/code-review-bot', + live: null, + stars: 89, + forks: 22, + contributors: 15, + lastUpdated: '2024-02-28', + status: 'active' + }, + { + id: 6, + title: 'Linux Distro Comparison', + description: 'Interactive comparison tool for different Linux distributions with detailed analysis.', + category: 'education', + tech: ['Vue.js', 'D3.js', 'Node.js', 'MongoDB'], + github: 'https://github.com/fossee-club/distro-compare', + live: 'https://distro-compare.fossee.org', + stars: 56, + forks: 11, + contributors: 9, + lastUpdated: '2024-02-25', + status: 'active' + } + ]; + + const categories = [ + { id: 'all', label: 'All Projects', color: 'text-white' }, + { id: 'web', label: 'Web Apps', color: 'text-green' }, + { id: 'mobile', label: 'Mobile Apps', color: 'text-cyan' }, + { id: 'tool', label: 'Tools', color: 'text-orange' }, + { id: 'education', label: 'Education', color: 'text-green' } + ]; + + const filteredProjects = projects.filter(project => + activeFilter === 'all' || project.category === activeFilter + ); + + const getStatusColor = (status) => { + switch (status) { + case 'active': return 'text-green'; + case 'development': return 'text-orange'; + case 'archived': return 'text-gray'; + default: return 'text-white'; + } + }; + + return ( + <div className="min-h-screen"> + {/* Hero Section */} + <section className="section"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 50 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8 }} + className="text-center mb-16" + > + <h1 className="text-4xl md:text-6xl font-bold mb-6"> + <span className="text-green neon-glow-green">Projects</span> & Contributions + </h1> + <p className="text-xl text-gray max-w-3xl mx-auto"> + Explore our open source projects, member contributions, and innovative solutions built by the FOSSEE community. + </p> + </motion.div> + </div> + </section> + + {/* Filters Section */} + <section className="section bg-secondary"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.2 }} + > + <h2 className="section-title">Browse Projects</h2> + <div className="flex flex-wrap justify-center gap-4 mb-8"> + {categories.map((category) => ( + <motion.button + key={category.id} + whileHover={{ scale: 1.05 }} + whileTap={{ scale: 0.95 }} + onClick={() => setActiveFilter(category.id)} + className={`flex items-center space-x-2 px-4 py-2 rounded border transition-colors ${ + activeFilter === category.id + ? 'border-green text-green bg-green bg-opacity-10' + : 'border-light-gray text-gray hover:border-green hover:text-green' + }`} + > + <Code className="w-4 h-4" /> + <span>{category.label}</span> + </motion.button> + ))} + </div> + </motion.div> + </div> + </section> + + {/* Projects Grid */} + <section className="section"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.4 }} + className="grid md:grid-cols-2 lg:grid-cols-3 gap-8" + > + {filteredProjects.map((project, index) => ( + <motion.div + key={project.id} + initial={{ opacity: 0, y: 20 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.5, delay: 0.1 * index }} + whileHover={{ y: -5 }} + className="card" + > + <div className="flex items-start justify-between mb-4"> + <Code className="w-8 h-8 text-green" /> + <span className={`text-sm px-2 py-1 rounded ${getStatusColor(project.status)} bg-opacity-10`}> + {project.status.toUpperCase()} + </span> + </div> + + <h3 className="text-xl font-bold mb-2 text-white">{project.title}</h3> + <p className="text-gray mb-4">{project.description}</p> + + {/* Tech Stack */} + <div className="flex flex-wrap gap-2 mb-4"> + {project.tech.map((tech, techIndex) => ( + <span + key={techIndex} + className="text-xs px-2 py-1 bg-cyan bg-opacity-10 text-cyan rounded" + > + {tech} + </span> + ))} + </div> + + {/* Stats */} + <div className="grid grid-cols-3 gap-4 mb-4 text-center"> + <div className="flex items-center justify-center space-x-1"> + <Star className="w-4 h-4 text-green" /> + <span className="text-sm text-gray">{project.stars}</span> + </div> + <div className="flex items-center justify-center space-x-1"> + <GitBranch className="w-4 h-4 text-cyan" /> + <span className="text-sm text-gray">{project.forks}</span> + </div> + <div className="flex items-center justify-center space-x-1"> + <Users className="w-4 h-4 text-green" /> + <span className="text-sm text-gray">{project.contributors}</span> + </div> + </div> + + {/* Last Updated */} + <div className="flex items-center space-x-2 text-sm text-gray mb-4"> + <Calendar className="w-4 h-4" /> + <span>Updated {project.lastUpdated}</span> + </div> + + {/* Action Buttons */} + <div className="flex space-x-2"> + <motion.a + href={project.github} + target="_blank" + rel="noopener noreferrer" + whileHover={{ scale: 1.02 }} + whileTap={{ scale: 0.98 }} + className="flex-1 btn flex items-center justify-center space-x-2" + > + <Github className="w-4 h-4" /> + <span>View Code</span> + </motion.a> + {project.live && ( + <motion.a + href={project.live} + target="_blank" + rel="noopener noreferrer" + whileHover={{ scale: 1.02 }} + whileTap={{ scale: 0.98 }} + className="btn flex items-center justify-center space-x-2" + > + <ExternalLink className="w-4 h-4" /> + <span>Live Demo</span> + </motion.a> + )} + </div> + </motion.div> + ))} + </motion.div> + + {filteredProjects.length === 0 && ( + <motion.div + initial={{ opacity: 0 }} + animate={{ opacity: 1 }} + className="text-center py-16" + > + <Code className="w-16 h-16 text-gray mx-auto mb-4" /> + <h3 className="text-xl font-bold mb-2 text-gray">No Projects Found</h3> + <p className="text-gray">Check back later for new projects or try a different filter.</p> + </motion.div> + )} + </div> + </section> + + {/* Contribution Stats */} + <section className="section bg-secondary"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.6 }} + > + <h2 className="section-title">Our Impact</h2> + <div className="grid md:grid-cols-4 gap-8"> + <div className="text-center"> + <div className="text-4xl font-bold text-green mb-2">15+</div> + <div className="text-gray">Open Source Projects</div> + </div> + <div className="text-center"> + <div className="text-4xl font-bold text-cyan mb-2">500+</div> + <div className="text-gray">GitHub Stars</div> + </div> + <div className="text-center"> + <div className="text-4xl font-bold text-green mb-2">50+</div> + <div className="text-gray">Active Contributors</div> + </div> + <div className="text-center"> + <div className="text-4xl font-bold text-cyan mb-2">1000+</div> + <div className="text-gray">Lines of Code</div> + </div> + </div> + </motion.div> + </div> + </section> + </div> + ); +}; + +export default Projects;
\ No newline at end of file diff --git a/src/pages/Resources.jsx b/src/pages/Resources.jsx new file mode 100644 index 0000000..ad5de73 --- /dev/null +++ b/src/pages/Resources.jsx @@ -0,0 +1,323 @@ +import React, { useState } from 'react'; +import { motion } from 'framer-motion'; +import { BookOpen, Code, Terminal, FileText, Video, Download, ExternalLink } from 'lucide-react'; + +const Resources = () => { + const [activeFilter, setActiveFilter] = useState('all'); + + const resources = [ + { + id: 1, + title: 'Linux Command Line Basics', + description: 'Complete guide to essential Linux commands for beginners.', + category: 'linux', + type: 'tutorial', + difficulty: 'beginner', + duration: '2 hours', + format: 'pdf', + downloadUrl: '/resources/linux-basics.pdf', + externalUrl: 'https://linuxjourney.com', + icon: Terminal + }, + { + id: 2, + title: 'Git & GitHub Mastery', + description: 'Learn version control with Git and collaboration on GitHub.', + category: 'git', + type: 'video', + difficulty: 'intermediate', + duration: '3 hours', + format: 'video', + downloadUrl: null, + externalUrl: 'https://youtube.com/watch?v=git-tutorial', + icon: Code + }, + { + id: 3, + title: 'Open Source Contribution Guide', + description: 'Step-by-step guide to contributing to open source projects.', + category: 'opensource', + type: 'guide', + difficulty: 'intermediate', + duration: '1 hour', + format: 'web', + downloadUrl: null, + externalUrl: 'https://opensource.guide', + icon: BookOpen + }, + { + id: 4, + title: 'Python for Beginners', + description: 'Learn Python programming from scratch with hands-on exercises.', + category: 'programming', + type: 'course', + difficulty: 'beginner', + duration: '8 hours', + format: 'interactive', + downloadUrl: '/resources/python-course.zip', + externalUrl: 'https://python.org/tutorial', + icon: Code + }, + { + id: 5, + title: 'Web Development with React', + description: 'Build modern web applications using React and open source tools.', + category: 'webdev', + type: 'tutorial', + difficulty: 'advanced', + duration: '6 hours', + format: 'video', + downloadUrl: null, + externalUrl: 'https://react.dev/learn', + icon: Code + }, + { + id: 6, + title: 'Linux System Administration', + description: 'Advanced Linux administration and server management.', + category: 'linux', + type: 'course', + difficulty: 'advanced', + duration: '12 hours', + format: 'pdf', + downloadUrl: '/resources/linux-admin.pdf', + externalUrl: 'https://linuxacademy.com', + icon: Terminal + } + ]; + + const categories = [ + { id: 'all', label: 'All Resources', icon: BookOpen }, + { id: 'linux', label: 'Linux', icon: Terminal }, + { id: 'programming', label: 'Programming', icon: Code }, + { id: 'git', label: 'Git & GitHub', icon: Code }, + { id: 'opensource', label: 'Open Source', icon: BookOpen }, + { id: 'webdev', label: 'Web Development', icon: Code } + ]; + + const filteredResources = resources.filter(resource => + activeFilter === 'all' || resource.category === activeFilter + ); + + const getDifficultyColor = (difficulty) => { + switch (difficulty) { + case 'beginner': return 'text-green'; + case 'intermediate': return 'text-orange'; + case 'advanced': return 'text-red'; + default: return 'text-white'; + } + }; + + const getFormatIcon = (format) => { + switch (format) { + case 'pdf': return FileText; + case 'video': return Video; + case 'web': return ExternalLink; + case 'interactive': return Code; + default: return BookOpen; + } + }; + + return ( + <div className="min-h-screen"> + {/* Hero Section */} + <section className="section"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 50 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8 }} + className="text-center mb-16" + > + <h1 className="text-4xl md:text-6xl font-bold mb-6"> + <span className="text-green neon-glow-green">Resources</span> & Learning + </h1> + <p className="text-xl text-gray max-w-3xl mx-auto"> + Access our curated collection of tutorials, guides, and documentation to enhance your skills + in Linux, programming, and open source development. + </p> + </motion.div> + </div> + </section> + + {/* Filters Section */} + <section className="section bg-secondary"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.2 }} + > + <h2 className="section-title">Browse Resources</h2> + <div className="flex flex-wrap justify-center gap-4 mb-8"> + {categories.map((category) => ( + <motion.button + key={category.id} + whileHover={{ scale: 1.05 }} + whileTap={{ scale: 0.95 }} + onClick={() => setActiveFilter(category.id)} + className={`flex items-center space-x-2 px-4 py-2 rounded border transition-colors ${ + activeFilter === category.id + ? 'border-green text-green bg-green bg-opacity-10' + : 'border-light-gray text-gray hover:border-green hover:text-green' + }`} + > + <category.icon className="w-4 h-4" /> + <span>{category.label}</span> + </motion.button> + ))} + </div> + </motion.div> + </div> + </section> + + {/* Resources Grid */} + <section className="section"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.4 }} + className="grid md:grid-cols-2 lg:grid-cols-3 gap-8" + > + {filteredResources.map((resource, index) => ( + <motion.div + key={resource.id} + initial={{ opacity: 0, y: 20 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.5, delay: 0.1 * index }} + whileHover={{ y: -5 }} + className="card" + > + <div className="flex items-start justify-between mb-4"> + <resource.icon className="w-8 h-8 text-green" /> + <span className={`text-sm px-2 py-1 rounded ${getDifficultyColor(resource.difficulty)} bg-opacity-10`}> + {resource.difficulty.toUpperCase()} + </span> + </div> + + <h3 className="text-xl font-bold mb-2 text-white">{resource.title}</h3> + <p className="text-gray mb-4">{resource.description}</p> + + <div className="space-y-2 mb-4"> + <div className="flex items-center space-x-2 text-sm"> + <BookOpen className="w-4 h-4 text-green" /> + <span className="text-gray">{resource.type}</span> + </div> + <div className="flex items-center space-x-2 text-sm"> + <Video className="w-4 h-4 text-cyan" /> + <span className="text-gray">{resource.duration}</span> + </div> + </div> + + {/* Action Buttons */} + <div className="flex space-x-2"> + {resource.downloadUrl && ( + <motion.a + href={resource.downloadUrl} + whileHover={{ scale: 1.02 }} + whileTap={{ scale: 0.98 }} + className="flex-1 btn flex items-center justify-center space-x-2" + > + <Download className="w-4 h-4" /> + <span>Download</span> + </motion.a> + )} + {resource.externalUrl && ( + <motion.a + href={resource.externalUrl} + target="_blank" + rel="noopener noreferrer" + whileHover={{ scale: 1.02 }} + whileTap={{ scale: 0.98 }} + className={`btn flex items-center justify-center space-x-2 ${!resource.downloadUrl ? 'flex-1' : ''}`} + > + <ExternalLink className="w-4 h-4" /> + <span>View</span> + </motion.a> + )} + </div> + </motion.div> + ))} + </motion.div> + + {filteredResources.length === 0 && ( + <motion.div + initial={{ opacity: 0 }} + animate={{ opacity: 1 }} + className="text-center py-16" + > + <BookOpen className="w-16 h-16 text-gray mx-auto mb-4" /> + <h3 className="text-xl font-bold mb-2 text-gray">No Resources Found</h3> + <p className="text-gray">Check back later for new resources or try a different filter.</p> + </motion.div> + )} + </div> + </section> + + {/* Quick Links Section */} + <section className="section bg-secondary"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.6 }} + > + <h2 className="section-title">Quick Links</h2> + <div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6"> + <motion.a + href="https://linuxjourney.com" + target="_blank" + rel="noopener noreferrer" + whileHover={{ y: -5 }} + className="card text-center" + > + <Terminal className="w-12 h-12 text-green mx-auto mb-4" /> + <h3 className="text-lg font-bold mb-2 text-white">Linux Journey</h3> + <p className="text-gray text-sm">Interactive Linux learning platform</p> + </motion.a> + + <motion.a + href="https://github.com" + target="_blank" + rel="noopener noreferrer" + whileHover={{ y: -5 }} + className="card text-center" + > + <Code className="w-12 h-12 text-cyan mx-auto mb-4" /> + <h3 className="text-lg font-bold mb-2 text-white">GitHub</h3> + <p className="text-gray text-sm">Discover and contribute to projects</p> + </motion.a> + + <motion.a + href="https://stackoverflow.com" + target="_blank" + rel="noopener noreferrer" + whileHover={{ y: -5 }} + className="card text-center" + > + <BookOpen className="w-12 h-12 text-green mx-auto mb-4" /> + <h3 className="text-lg font-bold mb-2 text-white">Stack Overflow</h3> + <p className="text-gray text-sm">Programming Q&A community</p> + </motion.a> + + <motion.a + href="https://opensource.guide" + target="_blank" + rel="noopener noreferrer" + whileHover={{ y: -5 }} + className="card text-center" + > + <FileText className="w-12 h-12 text-cyan mx-auto mb-4" /> + <h3 className="text-lg font-bold mb-2 text-white">Open Source Guide</h3> + <p className="text-gray text-sm">How to contribute to open source</p> + </motion.a> + </div> + </motion.div> + </div> + </section> + </div> + ); +}; + +export default Resources;
\ No newline at end of file diff --git a/src/pages/Team.jsx b/src/pages/Team.jsx new file mode 100644 index 0000000..9305f07 --- /dev/null +++ b/src/pages/Team.jsx @@ -0,0 +1,257 @@ +import React from 'react'; +import { motion } from 'framer-motion'; +import { Users, Github, Linkedin, Mail, Code, Terminal, BookOpen, Shield } from 'lucide-react'; + +const Team = () => { + const team = [ + { + id: 1, + name: 'Alex Chen', + role: 'Club President', + bio: 'Linux enthusiast and open source advocate. Passionate about making technology accessible to everyone.', + avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Alex', + github: 'https://github.com/alexchen', + linkedin: 'https://linkedin.com/in/alexchen', + email: 'alex@fossee-club.org', + skills: ['Linux', 'Python', 'DevOps'], + icon: Shield + }, + { + id: 2, + name: 'Sarah Kim', + role: 'Vice President', + bio: 'Full-stack developer with expertise in React and Node.js. Loves mentoring new developers.', + avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Sarah', + github: 'https://github.com/sarahkim', + linkedin: 'https://linkedin.com/in/sarahkim', + email: 'sarah@fossee-club.org', + skills: ['React', 'Node.js', 'TypeScript'], + icon: Code + }, + { + id: 3, + name: 'Marcus Rodriguez', + role: 'Technical Lead', + bio: 'System administrator and security expert. Specializes in Linux server management and cybersecurity.', + avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Marcus', + github: 'https://github.com/marcusrod', + linkedin: 'https://linkedin.com/in/marcusrod', + email: 'marcus@fossee-club.org', + skills: ['Linux Admin', 'Security', 'Bash'], + icon: Terminal + }, + { + id: 4, + name: 'Emma Thompson', + role: 'Education Coordinator', + bio: 'Dedicated to creating engaging learning experiences and fostering a supportive community.', + avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Emma', + github: 'https://github.com/emmathompson', + linkedin: 'https://linkedin.com/in/emmathompson', + email: 'emma@fossee-club.org', + skills: ['Teaching', 'Python', 'Git'], + icon: BookOpen + }, + { + id: 5, + name: 'David Park', + role: 'Events Manager', + bio: 'Organizes workshops, hackathons, and community events. Passionate about bringing people together.', + avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=David', + github: 'https://github.com/davidpark', + linkedin: 'https://linkedin.com/in/davidpark', + email: 'david@fossee-club.org', + skills: ['Event Planning', 'JavaScript', 'Docker'], + icon: Users + }, + { + id: 6, + name: 'Lisa Wang', + role: 'Outreach Coordinator', + bio: 'Builds partnerships with other tech communities and promotes open source values.', + avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Lisa', + github: 'https://github.com/lisawang', + linkedin: 'https://linkedin.com/in/lisawang', + email: 'lisa@fossee-club.org', + skills: ['Networking', 'Python', 'Open Source'], + icon: Users + } + ]; + + const stats = [ + { label: 'Active Members', value: '50+', icon: Users }, + { label: 'Projects Led', value: '15+', icon: Code }, + { label: 'Workshops Conducted', value: '25+', icon: BookOpen }, + { label: 'Years Combined Experience', value: '50+', icon: Shield } + ]; + + return ( + <div className="min-h-screen"> + {/* Hero Section */} + <section className="section"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 50 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8 }} + className="text-center mb-16" + > + <h1 className="text-4xl md:text-6xl font-bold mb-6"> + Meet Our <span className="text-green neon-glow-green">Team</span> + </h1> + <p className="text-xl text-gray max-w-3xl mx-auto"> + Get to know the passionate individuals who drive the FOSSEE club forward. + Our team brings together diverse skills and experiences to create an amazing community. + </p> + </motion.div> + </div> + </section> + + {/* Stats Section */} + <section className="section bg-secondary"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.2 }} + > + <h2 className="section-title">Our Impact</h2> + <div className="grid md:grid-cols-4 gap-8"> + {stats.map((stat, index) => ( + <motion.div + key={index} + initial={{ opacity: 0, y: 20 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.5, delay: 0.1 * index }} + className="text-center" + > + <stat.icon className="w-12 h-12 text-green mx-auto mb-4" /> + <div className="text-3xl font-bold text-green mb-2">{stat.value}</div> + <div className="text-gray">{stat.label}</div> + </motion.div> + ))} + </div> + </motion.div> + </div> + </section> + + {/* Team Grid */} + <section className="section"> + <div className="container mx-auto px-4"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.4 }} + > + <h2 className="section-title">Leadership Team</h2> + <div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8"> + {team.map((member, index) => ( + <motion.div + key={member.id} + initial={{ opacity: 0, y: 20 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.5, delay: 0.1 * index }} + whileHover={{ y: -5 }} + className="card text-center" + > + <div className="mb-6"> + <img + src={member.avatar} + alt={member.name} + className="w-24 h-24 rounded-full mx-auto mb-4 border-2 border-green" + /> + <h3 className="text-xl font-bold mb-1 text-white">{member.name}</h3> + <p className="text-green font-semibold mb-2">{member.role}</p> + <p className="text-gray text-sm mb-4">{member.bio}</p> + </div> + + {/* Skills */} + <div className="flex flex-wrap justify-center gap-2 mb-6"> + {member.skills.map((skill, skillIndex) => ( + <span + key={skillIndex} + className="text-xs px-2 py-1 bg-cyan bg-opacity-10 text-cyan rounded" + > + {skill} + </span> + ))} + </div> + + {/* Social Links */} + <div className="flex justify-center space-x-4"> + <motion.a + href={member.github} + target="_blank" + rel="noopener noreferrer" + whileHover={{ scale: 1.1 }} + whileTap={{ scale: 0.9 }} + className="text-gray hover:text-green transition-colors" + title="GitHub" + > + <Github className="w-5 h-5" /> + </motion.a> + <motion.a + href={member.linkedin} + target="_blank" + rel="noopener noreferrer" + whileHover={{ scale: 1.1 }} + whileTap={{ scale: 0.9 }} + className="text-gray hover:text-cyan transition-colors" + title="LinkedIn" + > + <Linkedin className="w-5 h-5" /> + </motion.a> + <motion.a + href={`mailto:${member.email}`} + whileHover={{ scale: 1.1 }} + whileTap={{ scale: 0.9 }} + className="text-gray hover:text-green transition-colors" + title="Email" + > + <Mail className="w-5 h-5" /> + </motion.a> + </div> + </motion.div> + ))} + </div> + </motion.div> + </div> + </section> + + {/* Join Team Section */} + <section className="section bg-secondary"> + <div className="container mx-auto px-4 text-center"> + <motion.div + initial={{ opacity: 0, y: 30 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.8, delay: 0.6 }} + > + <h2 className="text-3xl font-bold mb-4 text-green">Join Our Team</h2> + <p className="text-xl text-gray mb-8 max-w-2xl mx-auto"> + We're always looking for passionate individuals to join our leadership team. + If you're interested in contributing to our mission, we'd love to hear from you. + </p> + <div className="flex flex-wrap justify-center gap-4"> + <motion.button + whileHover={{ scale: 1.05 }} + whileTap={{ scale: 0.95 }} + className="btn text-lg px-8 py-4" + > + Apply for Leadership + </motion.button> + <motion.button + whileHover={{ scale: 1.05 }} + whileTap={{ scale: 0.95 }} + className="btn text-lg px-8 py-4" + > + Become a Member + </motion.button> + </div> + </motion.div> + </div> + </section> + </div> + ); +}; + +export default Team;
\ No newline at end of file diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..8b0f57b --- /dev/null +++ b/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], +}) |
