├── .github ├── dependabot.yml └── workflows │ ├── test.yml │ └── updater.yaml ├── .gitignore ├── .husky └── pre-push ├── .npmignore ├── .prettierignore ├── .prettierrc.json ├── LICENSE ├── README.md ├── babel.config.json ├── eslint.config.mjs ├── example ├── index.html ├── package.json ├── pnpm-lock.yaml ├── public │ └── favicon.ico ├── src │ ├── components │ │ ├── CodeBlock.tsx │ │ ├── Docs.tsx │ │ ├── Error.tsx │ │ └── ForkMe.tsx │ ├── index.tsx │ ├── styles.scss │ └── vite-env.d.ts └── vite.config.mts ├── package.json ├── pnpm-lock.yaml ├── preview.png ├── rollup.config.mjs ├── src ├── index.tsx ├── lib.ts └── types.ts └── tsconfig.json /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 2 | version: 2 3 | updates: 4 | - package-ecosystem: 'npm' 5 | directory: '/' 6 | schedule: 7 | interval: 'weekly' 8 | groups: 9 | dependencies: 10 | patterns: 11 | - '*' 12 | update-types: 13 | - 'minor' 14 | - 'patch' 15 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4.2.2 12 | - uses: actions/setup-node@v4.4.0 13 | with: 14 | node-version: 20 15 | 16 | - uses: pnpm/action-setup@v4.1.0 17 | name: Install pnpm 18 | with: 19 | version: 9 20 | run_install: false 21 | 22 | - name: Get pnpm store directory 23 | shell: bash 24 | run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV 25 | 26 | - uses: actions/cache@v4.2.3 27 | name: Setup pnpm cache 28 | with: 29 | path: ${{ env.STORE_PATH }} 30 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 31 | restore-keys: ${{ runner.os }}-pnpm-store- 32 | 33 | - name: Install dependencies 34 | run: pnpm install -r --ignore-scripts 35 | 36 | - name: Check formatting (Prettier) 37 | run: pnpx prettier -c . 38 | 39 | - name: Generate TypeScript types 40 | run: pnpm postbuild 41 | 42 | - name: Run type checks (TypeScript) 43 | run: pnpm tsc 44 | 45 | - name: Run linter (ESLint) 46 | run: pnpm lint 47 | -------------------------------------------------------------------------------- /.github/workflows/updater.yaml: -------------------------------------------------------------------------------- 1 | name: GitHub actions updater 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 0 * * 0' # every Sunday 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4.2.2 13 | with: 14 | token: ${{ secrets.WORKFLOW_SECRET }} # Access token with `workflow` scope 15 | 16 | - name: Run GitHub Actions Version Updater 17 | uses: saadmk11/github-actions-version-updater@v0.8.1 18 | with: 19 | # [Required] Access token with `workflow` scope. 20 | token: ${{ secrets.WORKFLOW_SECRET }} # Access token with `workflow` scope 21 | committer_username: 'Jonathan Gruber' 22 | committer_email: 'gruberjonathan@gmail.com' 23 | commit_message: 'Update GitHub actions' 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | 3 | build/ 4 | dist/ 5 | 6 | example/src/react-app-env.d.ts 7 | 8 | .env.* 9 | .log* 10 | 11 | .vscode/ 12 | .idea/ 13 | .DS_Store 14 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | pnpm check 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | 3 | !/dist/** 4 | !/src/** 5 | 6 | !package.json 7 | !LICENSE 8 | !README.md 9 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .npmignore 3 | .prettierignore 4 | pnpm-lock.yaml 5 | 6 | LICENSE 7 | 8 | *.directory 9 | *.lock 10 | *.ico 11 | *.png 12 | 13 | **/*/build/**/* 14 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["@ianvs/prettier-plugin-sort-imports"], 3 | "importOrder": ["", "^react$", "", "^[.]"], 4 | "importOrderParserPlugins": ["typescript", "jsx", "importAttributes"], 5 | "importOrderTypeScriptVersion": "5.7.0", 6 | "arrowParens": "avoid", 7 | "printWidth": 100, 8 | "proseWrap": "always", 9 | "singleQuote": true, 10 | "semi": false 11 | } 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Jonathan Gruber 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React GitHub Calendar 2 | 3 | [![CI](https://github.com/grubersjoe/react-github-calendar/actions/workflows/test.yml/badge.svg)](https://github.com/grubersjoe/react-github-calendar/actions/workflows/test.yml) 4 | [![npm version](https://badge.fury.io/js/react-github-calendar.svg)](https://www.npmjs.com/package/react-github-calendar) 5 | 6 | A React component to display a GitHub contributions graph based on 7 | [`react-activity-calendar`](https://github.com/grubersjoe/react-activity-calendar) and 8 | [`github-contributions-api`](https://github.com/grubersjoe/github-contributions-api). 9 | 10 | ![Screenshot](preview.png) 11 | 12 | [Demo and documentation](https://grubersjoe.github.io/react-github-calendar/) 13 | 14 | ## Installation 15 | 16 | ```shell 17 | npm install react-github-calendar 18 | ``` 19 | 20 | ## Usage 21 | 22 | ```tsx 23 | import GitHubCalendar from 'react-github-calendar' 24 | 25 | ; 26 | ``` 27 | 28 | ## FAQ 29 | 30 | ### Is server side rendering (SSR) supported? 31 | 32 | Yes. However, not with this component because it fetches data client-side. For SSR support, you can 33 | fetch the GitHub contribution data from a suitable 34 | [API](https://github.com/grubersjoe/github-contributions-api) server-side and pass it on to the 35 | internally used [`react-activity-calendar`](https://github.com/grubersjoe/react-activity-calendar) 36 | component. See the 37 | [source code](https://github.com/grubersjoe/react-github-calendar/blob/main/src/index.tsx) as 38 | example and the GitHub color theme. 39 | 40 | ### Why is Create React App unsupported? 41 | 42 | Create React App (CRA) is considered 43 | [abandoned](https://github.com/facebook/create-react-app/discussions/11086), and you probably should 44 | not use it anymore (more 45 | [background](https://github.com/facebook/create-react-app/issues/11180#issuecomment-874748552)). 46 | Using this component inside CRA will lead to errors for reasons described in issue 47 | [#105](https://github.com/grubersjoe/react-activity-calendar/issues/105) of 48 | `react-activity-calendar`. This repo is not for CRA support questions. If you encounter issues, you 49 | need to fix those yourself given the maintenance state of CRA. Personally, I would recommend using 50 | [Vite](https://vitejs.dev/) instead of CRA. It offers everything that CRA does and more. 51 | 52 | ## Development 53 | 54 | Start watch mode for the library first: 55 | 56 | ```shell 57 | npm install 58 | npm dev 59 | ``` 60 | 61 | Then start watch mode of example page: 62 | 63 | ```shell 64 | cd example 65 | npm install 66 | npm dev 67 | ``` 68 | 69 | Open http://localhost:3000. 70 | 71 | ### Publish a new release 72 | 73 | ```shell 74 | npm publish --dry-run 75 | 76 | # When you're happy 77 | npm publish --access=public 78 | ``` 79 | 80 | ### Update demo page 81 | 82 | ```shell 83 | npm run deploy 84 | ``` 85 | -------------------------------------------------------------------------------- /babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/preset-typescript", 5 | [ 6 | "@babel/preset-react", 7 | { 8 | "runtime": "automatic" 9 | } 10 | ] 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import eslint from '@eslint/js' 2 | import react from 'eslint-plugin-react' 3 | import reactHooks from 'eslint-plugin-react-hooks' 4 | import globals from 'globals' 5 | import typescript from 'typescript-eslint' 6 | 7 | export default typescript.config( 8 | eslint.configs.recommended, 9 | typescript.configs.strictTypeChecked, 10 | typescript.configs.stylisticTypeChecked, 11 | react.configs.flat.recommended, 12 | react.configs.flat['jsx-runtime'], 13 | reactHooks.configs['recommended-latest'], 14 | { 15 | rules: { 16 | 'no-console': 'error', 17 | '@typescript-eslint/array-type': ['error', { default: 'generic' }], 18 | '@typescript-eslint/consistent-type-definitions': ['error', 'type'], 19 | 'react/no-unescaped-entities': 'off', 20 | }, 21 | languageOptions: { 22 | globals: { 23 | ...globals.browser, 24 | }, 25 | parserOptions: { 26 | projectService: true, 27 | tsconfigRootDir: import.meta.dirname, 28 | }, 29 | }, 30 | settings: { 31 | react: { 32 | version: 'detect', 33 | }, 34 | }, 35 | }, 36 | { 37 | // Note: there must be no other properties in this object 38 | ignores: ['build/', 'public/', 'example/build/', 'rollup.config.mjs'], 39 | }, 40 | ) 41 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | React GitHub Calendar 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "tsc && vite build", 5 | "dev": "vite", 6 | "preview": "vite preview" 7 | }, 8 | "dependencies": { 9 | "react-error-boundary": "^6.0.0", 10 | "react-github-btn": "^1.4.0", 11 | "react-github-calendar": "link:..", 12 | "react-router": "^7.5.3", 13 | "react-syntax-highlighter": "^15.6.1" 14 | }, 15 | "devDependencies": { 16 | "@types/node": "^22.15.3", 17 | "@types/react": "^19.1.2", 18 | "@types/react-dom": "^19.1.3", 19 | "@types/react-syntax-highlighter": "^15.5.13", 20 | "@vitejs/plugin-react": "^4.4.1", 21 | "react": "^19.1.0", 22 | "react-dom": "^19.1.0", 23 | "sass": "^1.87.0", 24 | "typescript": "^5.8.3", 25 | "vite": "^6.3.5" 26 | }, 27 | "pnpm": { 28 | "onlyBuiltDependencies": [ 29 | "@parcel/watcher", 30 | "esbuild" 31 | ] 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /example/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | react-error-boundary: 12 | specifier: ^6.0.0 13 | version: 6.0.0(react@19.1.0) 14 | react-github-btn: 15 | specifier: ^1.4.0 16 | version: 1.4.0(react@19.1.0) 17 | react-github-calendar: 18 | specifier: link:.. 19 | version: link:.. 20 | react-router: 21 | specifier: ^7.5.3 22 | version: 7.5.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 23 | react-syntax-highlighter: 24 | specifier: ^15.6.1 25 | version: 15.6.1(react@19.1.0) 26 | devDependencies: 27 | '@types/node': 28 | specifier: ^22.15.3 29 | version: 22.15.3 30 | '@types/react': 31 | specifier: ^19.1.2 32 | version: 19.1.2 33 | '@types/react-dom': 34 | specifier: ^19.1.3 35 | version: 19.1.3(@types/react@19.1.2) 36 | '@types/react-syntax-highlighter': 37 | specifier: ^15.5.13 38 | version: 15.5.13 39 | '@vitejs/plugin-react': 40 | specifier: ^4.4.1 41 | version: 4.4.1(vite@6.3.5(@types/node@22.15.3)(sass@1.87.0)) 42 | react: 43 | specifier: ^19.1.0 44 | version: 19.1.0 45 | react-dom: 46 | specifier: ^19.1.0 47 | version: 19.1.0(react@19.1.0) 48 | sass: 49 | specifier: ^1.87.0 50 | version: 1.87.0 51 | typescript: 52 | specifier: ^5.8.3 53 | version: 5.8.3 54 | vite: 55 | specifier: ^6.3.5 56 | version: 6.3.5(@types/node@22.15.3)(sass@1.87.0) 57 | 58 | packages: 59 | 60 | '@ampproject/remapping@2.3.0': 61 | resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} 62 | engines: {node: '>=6.0.0'} 63 | 64 | '@babel/code-frame@7.27.1': 65 | resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} 66 | engines: {node: '>=6.9.0'} 67 | 68 | '@babel/compat-data@7.27.1': 69 | resolution: {integrity: sha512-Q+E+rd/yBzNQhXkG+zQnF58e4zoZfBedaxwzPmicKsiK3nt8iJYrSrDbjwFFDGC4f+rPafqRaPH6TsDoSvMf7A==} 70 | engines: {node: '>=6.9.0'} 71 | 72 | '@babel/core@7.27.1': 73 | resolution: {integrity: sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==} 74 | engines: {node: '>=6.9.0'} 75 | 76 | '@babel/generator@7.27.1': 77 | resolution: {integrity: sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==} 78 | engines: {node: '>=6.9.0'} 79 | 80 | '@babel/helper-compilation-targets@7.27.1': 81 | resolution: {integrity: sha512-2YaDd/Rd9E598B5+WIc8wJPmWETiiJXFYVE60oX8FDohv7rAUU3CQj+A1MgeEmcsk2+dQuEjIe/GDvig0SqL4g==} 82 | engines: {node: '>=6.9.0'} 83 | 84 | '@babel/helper-module-imports@7.27.1': 85 | resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} 86 | engines: {node: '>=6.9.0'} 87 | 88 | '@babel/helper-module-transforms@7.27.1': 89 | resolution: {integrity: sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==} 90 | engines: {node: '>=6.9.0'} 91 | peerDependencies: 92 | '@babel/core': ^7.0.0 93 | 94 | '@babel/helper-plugin-utils@7.27.1': 95 | resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} 96 | engines: {node: '>=6.9.0'} 97 | 98 | '@babel/helper-string-parser@7.27.1': 99 | resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} 100 | engines: {node: '>=6.9.0'} 101 | 102 | '@babel/helper-validator-identifier@7.27.1': 103 | resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} 104 | engines: {node: '>=6.9.0'} 105 | 106 | '@babel/helper-validator-option@7.27.1': 107 | resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} 108 | engines: {node: '>=6.9.0'} 109 | 110 | '@babel/helpers@7.27.1': 111 | resolution: {integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==} 112 | engines: {node: '>=6.9.0'} 113 | 114 | '@babel/parser@7.27.1': 115 | resolution: {integrity: sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ==} 116 | engines: {node: '>=6.0.0'} 117 | hasBin: true 118 | 119 | '@babel/plugin-transform-react-jsx-self@7.27.1': 120 | resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} 121 | engines: {node: '>=6.9.0'} 122 | peerDependencies: 123 | '@babel/core': ^7.0.0-0 124 | 125 | '@babel/plugin-transform-react-jsx-source@7.27.1': 126 | resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} 127 | engines: {node: '>=6.9.0'} 128 | peerDependencies: 129 | '@babel/core': ^7.0.0-0 130 | 131 | '@babel/runtime@7.25.7': 132 | resolution: {integrity: sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==} 133 | engines: {node: '>=6.9.0'} 134 | 135 | '@babel/runtime@7.27.1': 136 | resolution: {integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==} 137 | engines: {node: '>=6.9.0'} 138 | 139 | '@babel/template@7.27.1': 140 | resolution: {integrity: sha512-Fyo3ghWMqkHHpHQCoBs2VnYjR4iWFFjguTDEqA5WgZDOrFesVjMhMM2FSqTKSoUSDO1VQtavj8NFpdRBEvJTtg==} 141 | engines: {node: '>=6.9.0'} 142 | 143 | '@babel/traverse@7.27.1': 144 | resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==} 145 | engines: {node: '>=6.9.0'} 146 | 147 | '@babel/types@7.27.1': 148 | resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==} 149 | engines: {node: '>=6.9.0'} 150 | 151 | '@esbuild/aix-ppc64@0.25.3': 152 | resolution: {integrity: sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==} 153 | engines: {node: '>=18'} 154 | cpu: [ppc64] 155 | os: [aix] 156 | 157 | '@esbuild/android-arm64@0.25.3': 158 | resolution: {integrity: sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==} 159 | engines: {node: '>=18'} 160 | cpu: [arm64] 161 | os: [android] 162 | 163 | '@esbuild/android-arm@0.25.3': 164 | resolution: {integrity: sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==} 165 | engines: {node: '>=18'} 166 | cpu: [arm] 167 | os: [android] 168 | 169 | '@esbuild/android-x64@0.25.3': 170 | resolution: {integrity: sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==} 171 | engines: {node: '>=18'} 172 | cpu: [x64] 173 | os: [android] 174 | 175 | '@esbuild/darwin-arm64@0.25.3': 176 | resolution: {integrity: sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==} 177 | engines: {node: '>=18'} 178 | cpu: [arm64] 179 | os: [darwin] 180 | 181 | '@esbuild/darwin-x64@0.25.3': 182 | resolution: {integrity: sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==} 183 | engines: {node: '>=18'} 184 | cpu: [x64] 185 | os: [darwin] 186 | 187 | '@esbuild/freebsd-arm64@0.25.3': 188 | resolution: {integrity: sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==} 189 | engines: {node: '>=18'} 190 | cpu: [arm64] 191 | os: [freebsd] 192 | 193 | '@esbuild/freebsd-x64@0.25.3': 194 | resolution: {integrity: sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==} 195 | engines: {node: '>=18'} 196 | cpu: [x64] 197 | os: [freebsd] 198 | 199 | '@esbuild/linux-arm64@0.25.3': 200 | resolution: {integrity: sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==} 201 | engines: {node: '>=18'} 202 | cpu: [arm64] 203 | os: [linux] 204 | 205 | '@esbuild/linux-arm@0.25.3': 206 | resolution: {integrity: sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==} 207 | engines: {node: '>=18'} 208 | cpu: [arm] 209 | os: [linux] 210 | 211 | '@esbuild/linux-ia32@0.25.3': 212 | resolution: {integrity: sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==} 213 | engines: {node: '>=18'} 214 | cpu: [ia32] 215 | os: [linux] 216 | 217 | '@esbuild/linux-loong64@0.25.3': 218 | resolution: {integrity: sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==} 219 | engines: {node: '>=18'} 220 | cpu: [loong64] 221 | os: [linux] 222 | 223 | '@esbuild/linux-mips64el@0.25.3': 224 | resolution: {integrity: sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==} 225 | engines: {node: '>=18'} 226 | cpu: [mips64el] 227 | os: [linux] 228 | 229 | '@esbuild/linux-ppc64@0.25.3': 230 | resolution: {integrity: sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==} 231 | engines: {node: '>=18'} 232 | cpu: [ppc64] 233 | os: [linux] 234 | 235 | '@esbuild/linux-riscv64@0.25.3': 236 | resolution: {integrity: sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==} 237 | engines: {node: '>=18'} 238 | cpu: [riscv64] 239 | os: [linux] 240 | 241 | '@esbuild/linux-s390x@0.25.3': 242 | resolution: {integrity: sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==} 243 | engines: {node: '>=18'} 244 | cpu: [s390x] 245 | os: [linux] 246 | 247 | '@esbuild/linux-x64@0.25.3': 248 | resolution: {integrity: sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==} 249 | engines: {node: '>=18'} 250 | cpu: [x64] 251 | os: [linux] 252 | 253 | '@esbuild/netbsd-arm64@0.25.3': 254 | resolution: {integrity: sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==} 255 | engines: {node: '>=18'} 256 | cpu: [arm64] 257 | os: [netbsd] 258 | 259 | '@esbuild/netbsd-x64@0.25.3': 260 | resolution: {integrity: sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==} 261 | engines: {node: '>=18'} 262 | cpu: [x64] 263 | os: [netbsd] 264 | 265 | '@esbuild/openbsd-arm64@0.25.3': 266 | resolution: {integrity: sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==} 267 | engines: {node: '>=18'} 268 | cpu: [arm64] 269 | os: [openbsd] 270 | 271 | '@esbuild/openbsd-x64@0.25.3': 272 | resolution: {integrity: sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==} 273 | engines: {node: '>=18'} 274 | cpu: [x64] 275 | os: [openbsd] 276 | 277 | '@esbuild/sunos-x64@0.25.3': 278 | resolution: {integrity: sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==} 279 | engines: {node: '>=18'} 280 | cpu: [x64] 281 | os: [sunos] 282 | 283 | '@esbuild/win32-arm64@0.25.3': 284 | resolution: {integrity: sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==} 285 | engines: {node: '>=18'} 286 | cpu: [arm64] 287 | os: [win32] 288 | 289 | '@esbuild/win32-ia32@0.25.3': 290 | resolution: {integrity: sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==} 291 | engines: {node: '>=18'} 292 | cpu: [ia32] 293 | os: [win32] 294 | 295 | '@esbuild/win32-x64@0.25.3': 296 | resolution: {integrity: sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==} 297 | engines: {node: '>=18'} 298 | cpu: [x64] 299 | os: [win32] 300 | 301 | '@jridgewell/gen-mapping@0.3.8': 302 | resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} 303 | engines: {node: '>=6.0.0'} 304 | 305 | '@jridgewell/resolve-uri@3.1.2': 306 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 307 | engines: {node: '>=6.0.0'} 308 | 309 | '@jridgewell/set-array@1.2.1': 310 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 311 | engines: {node: '>=6.0.0'} 312 | 313 | '@jridgewell/sourcemap-codec@1.5.0': 314 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 315 | 316 | '@jridgewell/trace-mapping@0.3.25': 317 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 318 | 319 | '@parcel/watcher-android-arm64@2.5.1': 320 | resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} 321 | engines: {node: '>= 10.0.0'} 322 | cpu: [arm64] 323 | os: [android] 324 | 325 | '@parcel/watcher-darwin-arm64@2.5.1': 326 | resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} 327 | engines: {node: '>= 10.0.0'} 328 | cpu: [arm64] 329 | os: [darwin] 330 | 331 | '@parcel/watcher-darwin-x64@2.5.1': 332 | resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} 333 | engines: {node: '>= 10.0.0'} 334 | cpu: [x64] 335 | os: [darwin] 336 | 337 | '@parcel/watcher-freebsd-x64@2.5.1': 338 | resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} 339 | engines: {node: '>= 10.0.0'} 340 | cpu: [x64] 341 | os: [freebsd] 342 | 343 | '@parcel/watcher-linux-arm-glibc@2.5.1': 344 | resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} 345 | engines: {node: '>= 10.0.0'} 346 | cpu: [arm] 347 | os: [linux] 348 | 349 | '@parcel/watcher-linux-arm-musl@2.5.1': 350 | resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} 351 | engines: {node: '>= 10.0.0'} 352 | cpu: [arm] 353 | os: [linux] 354 | 355 | '@parcel/watcher-linux-arm64-glibc@2.5.1': 356 | resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} 357 | engines: {node: '>= 10.0.0'} 358 | cpu: [arm64] 359 | os: [linux] 360 | 361 | '@parcel/watcher-linux-arm64-musl@2.5.1': 362 | resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} 363 | engines: {node: '>= 10.0.0'} 364 | cpu: [arm64] 365 | os: [linux] 366 | 367 | '@parcel/watcher-linux-x64-glibc@2.5.1': 368 | resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} 369 | engines: {node: '>= 10.0.0'} 370 | cpu: [x64] 371 | os: [linux] 372 | 373 | '@parcel/watcher-linux-x64-musl@2.5.1': 374 | resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} 375 | engines: {node: '>= 10.0.0'} 376 | cpu: [x64] 377 | os: [linux] 378 | 379 | '@parcel/watcher-win32-arm64@2.5.1': 380 | resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} 381 | engines: {node: '>= 10.0.0'} 382 | cpu: [arm64] 383 | os: [win32] 384 | 385 | '@parcel/watcher-win32-ia32@2.5.1': 386 | resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} 387 | engines: {node: '>= 10.0.0'} 388 | cpu: [ia32] 389 | os: [win32] 390 | 391 | '@parcel/watcher-win32-x64@2.5.1': 392 | resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} 393 | engines: {node: '>= 10.0.0'} 394 | cpu: [x64] 395 | os: [win32] 396 | 397 | '@parcel/watcher@2.5.1': 398 | resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} 399 | engines: {node: '>= 10.0.0'} 400 | 401 | '@rollup/rollup-android-arm-eabi@4.40.1': 402 | resolution: {integrity: sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw==} 403 | cpu: [arm] 404 | os: [android] 405 | 406 | '@rollup/rollup-android-arm64@4.40.1': 407 | resolution: {integrity: sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw==} 408 | cpu: [arm64] 409 | os: [android] 410 | 411 | '@rollup/rollup-darwin-arm64@4.40.1': 412 | resolution: {integrity: sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA==} 413 | cpu: [arm64] 414 | os: [darwin] 415 | 416 | '@rollup/rollup-darwin-x64@4.40.1': 417 | resolution: {integrity: sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw==} 418 | cpu: [x64] 419 | os: [darwin] 420 | 421 | '@rollup/rollup-freebsd-arm64@4.40.1': 422 | resolution: {integrity: sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw==} 423 | cpu: [arm64] 424 | os: [freebsd] 425 | 426 | '@rollup/rollup-freebsd-x64@4.40.1': 427 | resolution: {integrity: sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q==} 428 | cpu: [x64] 429 | os: [freebsd] 430 | 431 | '@rollup/rollup-linux-arm-gnueabihf@4.40.1': 432 | resolution: {integrity: sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg==} 433 | cpu: [arm] 434 | os: [linux] 435 | 436 | '@rollup/rollup-linux-arm-musleabihf@4.40.1': 437 | resolution: {integrity: sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg==} 438 | cpu: [arm] 439 | os: [linux] 440 | 441 | '@rollup/rollup-linux-arm64-gnu@4.40.1': 442 | resolution: {integrity: sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg==} 443 | cpu: [arm64] 444 | os: [linux] 445 | 446 | '@rollup/rollup-linux-arm64-musl@4.40.1': 447 | resolution: {integrity: sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ==} 448 | cpu: [arm64] 449 | os: [linux] 450 | 451 | '@rollup/rollup-linux-loongarch64-gnu@4.40.1': 452 | resolution: {integrity: sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ==} 453 | cpu: [loong64] 454 | os: [linux] 455 | 456 | '@rollup/rollup-linux-powerpc64le-gnu@4.40.1': 457 | resolution: {integrity: sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg==} 458 | cpu: [ppc64] 459 | os: [linux] 460 | 461 | '@rollup/rollup-linux-riscv64-gnu@4.40.1': 462 | resolution: {integrity: sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ==} 463 | cpu: [riscv64] 464 | os: [linux] 465 | 466 | '@rollup/rollup-linux-riscv64-musl@4.40.1': 467 | resolution: {integrity: sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA==} 468 | cpu: [riscv64] 469 | os: [linux] 470 | 471 | '@rollup/rollup-linux-s390x-gnu@4.40.1': 472 | resolution: {integrity: sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg==} 473 | cpu: [s390x] 474 | os: [linux] 475 | 476 | '@rollup/rollup-linux-x64-gnu@4.40.1': 477 | resolution: {integrity: sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==} 478 | cpu: [x64] 479 | os: [linux] 480 | 481 | '@rollup/rollup-linux-x64-musl@4.40.1': 482 | resolution: {integrity: sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==} 483 | cpu: [x64] 484 | os: [linux] 485 | 486 | '@rollup/rollup-win32-arm64-msvc@4.40.1': 487 | resolution: {integrity: sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==} 488 | cpu: [arm64] 489 | os: [win32] 490 | 491 | '@rollup/rollup-win32-ia32-msvc@4.40.1': 492 | resolution: {integrity: sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA==} 493 | cpu: [ia32] 494 | os: [win32] 495 | 496 | '@rollup/rollup-win32-x64-msvc@4.40.1': 497 | resolution: {integrity: sha512-ECyOuDeH3C1I8jH2MK1RtBJW+YPMvSfT0a5NN0nHfQYnDSJ6tUiZH3gzwVP5/Kfh/+Tt7tpWVF9LXNTnhTJ3kA==} 498 | cpu: [x64] 499 | os: [win32] 500 | 501 | '@types/babel__core@7.20.5': 502 | resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} 503 | 504 | '@types/babel__generator@7.27.0': 505 | resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} 506 | 507 | '@types/babel__template@7.4.4': 508 | resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} 509 | 510 | '@types/babel__traverse@7.20.7': 511 | resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} 512 | 513 | '@types/estree@1.0.7': 514 | resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} 515 | 516 | '@types/hast@2.3.10': 517 | resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==} 518 | 519 | '@types/node@22.15.3': 520 | resolution: {integrity: sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==} 521 | 522 | '@types/react-dom@19.1.3': 523 | resolution: {integrity: sha512-rJXC08OG0h3W6wDMFxQrZF00Kq6qQvw0djHRdzl3U5DnIERz0MRce3WVc7IS6JYBwtaP/DwYtRRjVlvivNveKg==} 524 | peerDependencies: 525 | '@types/react': ^19.0.0 526 | 527 | '@types/react-syntax-highlighter@15.5.13': 528 | resolution: {integrity: sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==} 529 | 530 | '@types/react@19.1.2': 531 | resolution: {integrity: sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==} 532 | 533 | '@types/unist@2.0.11': 534 | resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} 535 | 536 | '@vitejs/plugin-react@4.4.1': 537 | resolution: {integrity: sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w==} 538 | engines: {node: ^14.18.0 || >=16.0.0} 539 | peerDependencies: 540 | vite: ^4.2.0 || ^5.0.0 || ^6.0.0 541 | 542 | braces@3.0.3: 543 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 544 | engines: {node: '>=8'} 545 | 546 | browserslist@4.24.5: 547 | resolution: {integrity: sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==} 548 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 549 | hasBin: true 550 | 551 | caniuse-lite@1.0.30001717: 552 | resolution: {integrity: sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==} 553 | 554 | character-entities-legacy@1.1.4: 555 | resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} 556 | 557 | character-entities@1.2.4: 558 | resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==} 559 | 560 | character-reference-invalid@1.1.4: 561 | resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==} 562 | 563 | chokidar@4.0.3: 564 | resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} 565 | engines: {node: '>= 14.16.0'} 566 | 567 | comma-separated-tokens@1.0.8: 568 | resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==} 569 | 570 | convert-source-map@2.0.0: 571 | resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} 572 | 573 | cookie@1.0.2: 574 | resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} 575 | engines: {node: '>=18'} 576 | 577 | csstype@3.1.3: 578 | resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} 579 | 580 | debug@4.4.0: 581 | resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} 582 | engines: {node: '>=6.0'} 583 | peerDependencies: 584 | supports-color: '*' 585 | peerDependenciesMeta: 586 | supports-color: 587 | optional: true 588 | 589 | detect-libc@1.0.3: 590 | resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} 591 | engines: {node: '>=0.10'} 592 | hasBin: true 593 | 594 | electron-to-chromium@1.5.149: 595 | resolution: {integrity: sha512-UyiO82eb9dVOx8YO3ajDf9jz2kKyt98DEITRdeLPstOEuTlLzDA4Gyq5K9he71TQziU5jUVu2OAu5N48HmQiyQ==} 596 | 597 | esbuild@0.25.3: 598 | resolution: {integrity: sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==} 599 | engines: {node: '>=18'} 600 | hasBin: true 601 | 602 | escalade@3.2.0: 603 | resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} 604 | engines: {node: '>=6'} 605 | 606 | fault@1.0.4: 607 | resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==} 608 | 609 | fdir@6.4.4: 610 | resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} 611 | peerDependencies: 612 | picomatch: ^3 || ^4 613 | peerDependenciesMeta: 614 | picomatch: 615 | optional: true 616 | 617 | fill-range@7.1.1: 618 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 619 | engines: {node: '>=8'} 620 | 621 | format@0.2.2: 622 | resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} 623 | engines: {node: '>=0.4.x'} 624 | 625 | fsevents@2.3.3: 626 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 627 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 628 | os: [darwin] 629 | 630 | gensync@1.0.0-beta.2: 631 | resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} 632 | engines: {node: '>=6.9.0'} 633 | 634 | github-buttons@2.27.0: 635 | resolution: {integrity: sha512-PmfRMI2Rttg/2jDfKBeSl621sEznrsKF019SuoLdoNlO7qRUZaOyEI5Li4uW+79pVqnDtKfIEVuHTIJ5lgy64w==} 636 | 637 | globals@11.12.0: 638 | resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} 639 | engines: {node: '>=4'} 640 | 641 | hast-util-parse-selector@2.2.5: 642 | resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==} 643 | 644 | hastscript@6.0.0: 645 | resolution: {integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==} 646 | 647 | highlight.js@10.7.3: 648 | resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} 649 | 650 | highlightjs-vue@1.0.0: 651 | resolution: {integrity: sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==} 652 | 653 | immutable@5.1.1: 654 | resolution: {integrity: sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==} 655 | 656 | is-alphabetical@1.0.4: 657 | resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} 658 | 659 | is-alphanumerical@1.0.4: 660 | resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==} 661 | 662 | is-decimal@1.0.4: 663 | resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} 664 | 665 | is-extglob@2.1.1: 666 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 667 | engines: {node: '>=0.10.0'} 668 | 669 | is-glob@4.0.3: 670 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 671 | engines: {node: '>=0.10.0'} 672 | 673 | is-hexadecimal@1.0.4: 674 | resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==} 675 | 676 | is-number@7.0.0: 677 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 678 | engines: {node: '>=0.12.0'} 679 | 680 | js-tokens@4.0.0: 681 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 682 | 683 | jsesc@3.1.0: 684 | resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} 685 | engines: {node: '>=6'} 686 | hasBin: true 687 | 688 | json5@2.2.3: 689 | resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} 690 | engines: {node: '>=6'} 691 | hasBin: true 692 | 693 | lowlight@1.20.0: 694 | resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==} 695 | 696 | lru-cache@5.1.1: 697 | resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} 698 | 699 | micromatch@4.0.8: 700 | resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} 701 | engines: {node: '>=8.6'} 702 | 703 | ms@2.1.3: 704 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 705 | 706 | nanoid@3.3.11: 707 | resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} 708 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 709 | hasBin: true 710 | 711 | node-addon-api@7.1.1: 712 | resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} 713 | 714 | node-releases@2.0.19: 715 | resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} 716 | 717 | parse-entities@2.0.0: 718 | resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} 719 | 720 | picocolors@1.1.1: 721 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 722 | 723 | picomatch@2.3.1: 724 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 725 | engines: {node: '>=8.6'} 726 | 727 | picomatch@4.0.2: 728 | resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} 729 | engines: {node: '>=12'} 730 | 731 | postcss@8.5.3: 732 | resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} 733 | engines: {node: ^10 || ^12 || >=14} 734 | 735 | prismjs@1.27.0: 736 | resolution: {integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==} 737 | engines: {node: '>=6'} 738 | 739 | prismjs@1.29.0: 740 | resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} 741 | engines: {node: '>=6'} 742 | 743 | property-information@5.6.0: 744 | resolution: {integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==} 745 | 746 | react-dom@19.1.0: 747 | resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} 748 | peerDependencies: 749 | react: ^19.1.0 750 | 751 | react-error-boundary@6.0.0: 752 | resolution: {integrity: sha512-gdlJjD7NWr0IfkPlaREN2d9uUZUlksrfOx7SX62VRerwXbMY6ftGCIZua1VG1aXFNOimhISsTq+Owp725b9SiA==} 753 | peerDependencies: 754 | react: '>=16.13.1' 755 | 756 | react-github-btn@1.4.0: 757 | resolution: {integrity: sha512-lV4FYClAfjWnBfv0iNlJUGhamDgIq6TayD0kPZED6VzHWdpcHmPfsYOZ/CFwLfPv4Zp+F4m8QKTj0oy2HjiGXg==} 758 | peerDependencies: 759 | react: '>=16.3.0' 760 | 761 | react-refresh@0.17.0: 762 | resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} 763 | engines: {node: '>=0.10.0'} 764 | 765 | react-router@7.5.3: 766 | resolution: {integrity: sha512-3iUDM4/fZCQ89SXlDa+Ph3MevBrozBAI655OAfWQlTm9nBR0IKlrmNwFow5lPHttbwvITZfkeeeZFP6zt3F7pw==} 767 | engines: {node: '>=20.0.0'} 768 | peerDependencies: 769 | react: '>=18' 770 | react-dom: '>=18' 771 | peerDependenciesMeta: 772 | react-dom: 773 | optional: true 774 | 775 | react-syntax-highlighter@15.6.1: 776 | resolution: {integrity: sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg==} 777 | peerDependencies: 778 | react: '>= 0.14.0' 779 | 780 | react@19.1.0: 781 | resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} 782 | engines: {node: '>=0.10.0'} 783 | 784 | readdirp@4.1.2: 785 | resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} 786 | engines: {node: '>= 14.18.0'} 787 | 788 | refractor@3.6.0: 789 | resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==} 790 | 791 | regenerator-runtime@0.14.1: 792 | resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} 793 | 794 | rollup@4.40.1: 795 | resolution: {integrity: sha512-C5VvvgCCyfyotVITIAv+4efVytl5F7wt+/I2i9q9GZcEXW9BP52YYOXC58igUi+LFZVHukErIIqQSWwv/M3WRw==} 796 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 797 | hasBin: true 798 | 799 | sass@1.87.0: 800 | resolution: {integrity: sha512-d0NoFH4v6SjEK7BoX810Jsrhj7IQSYHAHLi/iSpgqKc7LaIDshFRlSg5LOymf9FqQhxEHs2W5ZQXlvy0KD45Uw==} 801 | engines: {node: '>=14.0.0'} 802 | hasBin: true 803 | 804 | scheduler@0.26.0: 805 | resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} 806 | 807 | semver@6.3.1: 808 | resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} 809 | hasBin: true 810 | 811 | set-cookie-parser@2.7.1: 812 | resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} 813 | 814 | source-map-js@1.2.1: 815 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 816 | engines: {node: '>=0.10.0'} 817 | 818 | space-separated-tokens@1.1.5: 819 | resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==} 820 | 821 | tinyglobby@0.2.13: 822 | resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} 823 | engines: {node: '>=12.0.0'} 824 | 825 | to-regex-range@5.0.1: 826 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 827 | engines: {node: '>=8.0'} 828 | 829 | turbo-stream@2.4.0: 830 | resolution: {integrity: sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==} 831 | 832 | typescript@5.8.3: 833 | resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} 834 | engines: {node: '>=14.17'} 835 | hasBin: true 836 | 837 | undici-types@6.21.0: 838 | resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} 839 | 840 | update-browserslist-db@1.1.3: 841 | resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} 842 | hasBin: true 843 | peerDependencies: 844 | browserslist: '>= 4.21.0' 845 | 846 | vite@6.3.5: 847 | resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} 848 | engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} 849 | hasBin: true 850 | peerDependencies: 851 | '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 852 | jiti: '>=1.21.0' 853 | less: '*' 854 | lightningcss: ^1.21.0 855 | sass: '*' 856 | sass-embedded: '*' 857 | stylus: '*' 858 | sugarss: '*' 859 | terser: ^5.16.0 860 | tsx: ^4.8.1 861 | yaml: ^2.4.2 862 | peerDependenciesMeta: 863 | '@types/node': 864 | optional: true 865 | jiti: 866 | optional: true 867 | less: 868 | optional: true 869 | lightningcss: 870 | optional: true 871 | sass: 872 | optional: true 873 | sass-embedded: 874 | optional: true 875 | stylus: 876 | optional: true 877 | sugarss: 878 | optional: true 879 | terser: 880 | optional: true 881 | tsx: 882 | optional: true 883 | yaml: 884 | optional: true 885 | 886 | xtend@4.0.2: 887 | resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} 888 | engines: {node: '>=0.4'} 889 | 890 | yallist@3.1.1: 891 | resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} 892 | 893 | snapshots: 894 | 895 | '@ampproject/remapping@2.3.0': 896 | dependencies: 897 | '@jridgewell/gen-mapping': 0.3.8 898 | '@jridgewell/trace-mapping': 0.3.25 899 | 900 | '@babel/code-frame@7.27.1': 901 | dependencies: 902 | '@babel/helper-validator-identifier': 7.27.1 903 | js-tokens: 4.0.0 904 | picocolors: 1.1.1 905 | 906 | '@babel/compat-data@7.27.1': {} 907 | 908 | '@babel/core@7.27.1': 909 | dependencies: 910 | '@ampproject/remapping': 2.3.0 911 | '@babel/code-frame': 7.27.1 912 | '@babel/generator': 7.27.1 913 | '@babel/helper-compilation-targets': 7.27.1 914 | '@babel/helper-module-transforms': 7.27.1(@babel/core@7.27.1) 915 | '@babel/helpers': 7.27.1 916 | '@babel/parser': 7.27.1 917 | '@babel/template': 7.27.1 918 | '@babel/traverse': 7.27.1 919 | '@babel/types': 7.27.1 920 | convert-source-map: 2.0.0 921 | debug: 4.4.0 922 | gensync: 1.0.0-beta.2 923 | json5: 2.2.3 924 | semver: 6.3.1 925 | transitivePeerDependencies: 926 | - supports-color 927 | 928 | '@babel/generator@7.27.1': 929 | dependencies: 930 | '@babel/parser': 7.27.1 931 | '@babel/types': 7.27.1 932 | '@jridgewell/gen-mapping': 0.3.8 933 | '@jridgewell/trace-mapping': 0.3.25 934 | jsesc: 3.1.0 935 | 936 | '@babel/helper-compilation-targets@7.27.1': 937 | dependencies: 938 | '@babel/compat-data': 7.27.1 939 | '@babel/helper-validator-option': 7.27.1 940 | browserslist: 4.24.5 941 | lru-cache: 5.1.1 942 | semver: 6.3.1 943 | 944 | '@babel/helper-module-imports@7.27.1': 945 | dependencies: 946 | '@babel/traverse': 7.27.1 947 | '@babel/types': 7.27.1 948 | transitivePeerDependencies: 949 | - supports-color 950 | 951 | '@babel/helper-module-transforms@7.27.1(@babel/core@7.27.1)': 952 | dependencies: 953 | '@babel/core': 7.27.1 954 | '@babel/helper-module-imports': 7.27.1 955 | '@babel/helper-validator-identifier': 7.27.1 956 | '@babel/traverse': 7.27.1 957 | transitivePeerDependencies: 958 | - supports-color 959 | 960 | '@babel/helper-plugin-utils@7.27.1': {} 961 | 962 | '@babel/helper-string-parser@7.27.1': {} 963 | 964 | '@babel/helper-validator-identifier@7.27.1': {} 965 | 966 | '@babel/helper-validator-option@7.27.1': {} 967 | 968 | '@babel/helpers@7.27.1': 969 | dependencies: 970 | '@babel/template': 7.27.1 971 | '@babel/types': 7.27.1 972 | 973 | '@babel/parser@7.27.1': 974 | dependencies: 975 | '@babel/types': 7.27.1 976 | 977 | '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.27.1)': 978 | dependencies: 979 | '@babel/core': 7.27.1 980 | '@babel/helper-plugin-utils': 7.27.1 981 | 982 | '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.27.1)': 983 | dependencies: 984 | '@babel/core': 7.27.1 985 | '@babel/helper-plugin-utils': 7.27.1 986 | 987 | '@babel/runtime@7.25.7': 988 | dependencies: 989 | regenerator-runtime: 0.14.1 990 | 991 | '@babel/runtime@7.27.1': {} 992 | 993 | '@babel/template@7.27.1': 994 | dependencies: 995 | '@babel/code-frame': 7.27.1 996 | '@babel/parser': 7.27.1 997 | '@babel/types': 7.27.1 998 | 999 | '@babel/traverse@7.27.1': 1000 | dependencies: 1001 | '@babel/code-frame': 7.27.1 1002 | '@babel/generator': 7.27.1 1003 | '@babel/parser': 7.27.1 1004 | '@babel/template': 7.27.1 1005 | '@babel/types': 7.27.1 1006 | debug: 4.4.0 1007 | globals: 11.12.0 1008 | transitivePeerDependencies: 1009 | - supports-color 1010 | 1011 | '@babel/types@7.27.1': 1012 | dependencies: 1013 | '@babel/helper-string-parser': 7.27.1 1014 | '@babel/helper-validator-identifier': 7.27.1 1015 | 1016 | '@esbuild/aix-ppc64@0.25.3': 1017 | optional: true 1018 | 1019 | '@esbuild/android-arm64@0.25.3': 1020 | optional: true 1021 | 1022 | '@esbuild/android-arm@0.25.3': 1023 | optional: true 1024 | 1025 | '@esbuild/android-x64@0.25.3': 1026 | optional: true 1027 | 1028 | '@esbuild/darwin-arm64@0.25.3': 1029 | optional: true 1030 | 1031 | '@esbuild/darwin-x64@0.25.3': 1032 | optional: true 1033 | 1034 | '@esbuild/freebsd-arm64@0.25.3': 1035 | optional: true 1036 | 1037 | '@esbuild/freebsd-x64@0.25.3': 1038 | optional: true 1039 | 1040 | '@esbuild/linux-arm64@0.25.3': 1041 | optional: true 1042 | 1043 | '@esbuild/linux-arm@0.25.3': 1044 | optional: true 1045 | 1046 | '@esbuild/linux-ia32@0.25.3': 1047 | optional: true 1048 | 1049 | '@esbuild/linux-loong64@0.25.3': 1050 | optional: true 1051 | 1052 | '@esbuild/linux-mips64el@0.25.3': 1053 | optional: true 1054 | 1055 | '@esbuild/linux-ppc64@0.25.3': 1056 | optional: true 1057 | 1058 | '@esbuild/linux-riscv64@0.25.3': 1059 | optional: true 1060 | 1061 | '@esbuild/linux-s390x@0.25.3': 1062 | optional: true 1063 | 1064 | '@esbuild/linux-x64@0.25.3': 1065 | optional: true 1066 | 1067 | '@esbuild/netbsd-arm64@0.25.3': 1068 | optional: true 1069 | 1070 | '@esbuild/netbsd-x64@0.25.3': 1071 | optional: true 1072 | 1073 | '@esbuild/openbsd-arm64@0.25.3': 1074 | optional: true 1075 | 1076 | '@esbuild/openbsd-x64@0.25.3': 1077 | optional: true 1078 | 1079 | '@esbuild/sunos-x64@0.25.3': 1080 | optional: true 1081 | 1082 | '@esbuild/win32-arm64@0.25.3': 1083 | optional: true 1084 | 1085 | '@esbuild/win32-ia32@0.25.3': 1086 | optional: true 1087 | 1088 | '@esbuild/win32-x64@0.25.3': 1089 | optional: true 1090 | 1091 | '@jridgewell/gen-mapping@0.3.8': 1092 | dependencies: 1093 | '@jridgewell/set-array': 1.2.1 1094 | '@jridgewell/sourcemap-codec': 1.5.0 1095 | '@jridgewell/trace-mapping': 0.3.25 1096 | 1097 | '@jridgewell/resolve-uri@3.1.2': {} 1098 | 1099 | '@jridgewell/set-array@1.2.1': {} 1100 | 1101 | '@jridgewell/sourcemap-codec@1.5.0': {} 1102 | 1103 | '@jridgewell/trace-mapping@0.3.25': 1104 | dependencies: 1105 | '@jridgewell/resolve-uri': 3.1.2 1106 | '@jridgewell/sourcemap-codec': 1.5.0 1107 | 1108 | '@parcel/watcher-android-arm64@2.5.1': 1109 | optional: true 1110 | 1111 | '@parcel/watcher-darwin-arm64@2.5.1': 1112 | optional: true 1113 | 1114 | '@parcel/watcher-darwin-x64@2.5.1': 1115 | optional: true 1116 | 1117 | '@parcel/watcher-freebsd-x64@2.5.1': 1118 | optional: true 1119 | 1120 | '@parcel/watcher-linux-arm-glibc@2.5.1': 1121 | optional: true 1122 | 1123 | '@parcel/watcher-linux-arm-musl@2.5.1': 1124 | optional: true 1125 | 1126 | '@parcel/watcher-linux-arm64-glibc@2.5.1': 1127 | optional: true 1128 | 1129 | '@parcel/watcher-linux-arm64-musl@2.5.1': 1130 | optional: true 1131 | 1132 | '@parcel/watcher-linux-x64-glibc@2.5.1': 1133 | optional: true 1134 | 1135 | '@parcel/watcher-linux-x64-musl@2.5.1': 1136 | optional: true 1137 | 1138 | '@parcel/watcher-win32-arm64@2.5.1': 1139 | optional: true 1140 | 1141 | '@parcel/watcher-win32-ia32@2.5.1': 1142 | optional: true 1143 | 1144 | '@parcel/watcher-win32-x64@2.5.1': 1145 | optional: true 1146 | 1147 | '@parcel/watcher@2.5.1': 1148 | dependencies: 1149 | detect-libc: 1.0.3 1150 | is-glob: 4.0.3 1151 | micromatch: 4.0.8 1152 | node-addon-api: 7.1.1 1153 | optionalDependencies: 1154 | '@parcel/watcher-android-arm64': 2.5.1 1155 | '@parcel/watcher-darwin-arm64': 2.5.1 1156 | '@parcel/watcher-darwin-x64': 2.5.1 1157 | '@parcel/watcher-freebsd-x64': 2.5.1 1158 | '@parcel/watcher-linux-arm-glibc': 2.5.1 1159 | '@parcel/watcher-linux-arm-musl': 2.5.1 1160 | '@parcel/watcher-linux-arm64-glibc': 2.5.1 1161 | '@parcel/watcher-linux-arm64-musl': 2.5.1 1162 | '@parcel/watcher-linux-x64-glibc': 2.5.1 1163 | '@parcel/watcher-linux-x64-musl': 2.5.1 1164 | '@parcel/watcher-win32-arm64': 2.5.1 1165 | '@parcel/watcher-win32-ia32': 2.5.1 1166 | '@parcel/watcher-win32-x64': 2.5.1 1167 | optional: true 1168 | 1169 | '@rollup/rollup-android-arm-eabi@4.40.1': 1170 | optional: true 1171 | 1172 | '@rollup/rollup-android-arm64@4.40.1': 1173 | optional: true 1174 | 1175 | '@rollup/rollup-darwin-arm64@4.40.1': 1176 | optional: true 1177 | 1178 | '@rollup/rollup-darwin-x64@4.40.1': 1179 | optional: true 1180 | 1181 | '@rollup/rollup-freebsd-arm64@4.40.1': 1182 | optional: true 1183 | 1184 | '@rollup/rollup-freebsd-x64@4.40.1': 1185 | optional: true 1186 | 1187 | '@rollup/rollup-linux-arm-gnueabihf@4.40.1': 1188 | optional: true 1189 | 1190 | '@rollup/rollup-linux-arm-musleabihf@4.40.1': 1191 | optional: true 1192 | 1193 | '@rollup/rollup-linux-arm64-gnu@4.40.1': 1194 | optional: true 1195 | 1196 | '@rollup/rollup-linux-arm64-musl@4.40.1': 1197 | optional: true 1198 | 1199 | '@rollup/rollup-linux-loongarch64-gnu@4.40.1': 1200 | optional: true 1201 | 1202 | '@rollup/rollup-linux-powerpc64le-gnu@4.40.1': 1203 | optional: true 1204 | 1205 | '@rollup/rollup-linux-riscv64-gnu@4.40.1': 1206 | optional: true 1207 | 1208 | '@rollup/rollup-linux-riscv64-musl@4.40.1': 1209 | optional: true 1210 | 1211 | '@rollup/rollup-linux-s390x-gnu@4.40.1': 1212 | optional: true 1213 | 1214 | '@rollup/rollup-linux-x64-gnu@4.40.1': 1215 | optional: true 1216 | 1217 | '@rollup/rollup-linux-x64-musl@4.40.1': 1218 | optional: true 1219 | 1220 | '@rollup/rollup-win32-arm64-msvc@4.40.1': 1221 | optional: true 1222 | 1223 | '@rollup/rollup-win32-ia32-msvc@4.40.1': 1224 | optional: true 1225 | 1226 | '@rollup/rollup-win32-x64-msvc@4.40.1': 1227 | optional: true 1228 | 1229 | '@types/babel__core@7.20.5': 1230 | dependencies: 1231 | '@babel/parser': 7.27.1 1232 | '@babel/types': 7.27.1 1233 | '@types/babel__generator': 7.27.0 1234 | '@types/babel__template': 7.4.4 1235 | '@types/babel__traverse': 7.20.7 1236 | 1237 | '@types/babel__generator@7.27.0': 1238 | dependencies: 1239 | '@babel/types': 7.27.1 1240 | 1241 | '@types/babel__template@7.4.4': 1242 | dependencies: 1243 | '@babel/parser': 7.27.1 1244 | '@babel/types': 7.27.1 1245 | 1246 | '@types/babel__traverse@7.20.7': 1247 | dependencies: 1248 | '@babel/types': 7.27.1 1249 | 1250 | '@types/estree@1.0.7': {} 1251 | 1252 | '@types/hast@2.3.10': 1253 | dependencies: 1254 | '@types/unist': 2.0.11 1255 | 1256 | '@types/node@22.15.3': 1257 | dependencies: 1258 | undici-types: 6.21.0 1259 | 1260 | '@types/react-dom@19.1.3(@types/react@19.1.2)': 1261 | dependencies: 1262 | '@types/react': 19.1.2 1263 | 1264 | '@types/react-syntax-highlighter@15.5.13': 1265 | dependencies: 1266 | '@types/react': 19.1.2 1267 | 1268 | '@types/react@19.1.2': 1269 | dependencies: 1270 | csstype: 3.1.3 1271 | 1272 | '@types/unist@2.0.11': {} 1273 | 1274 | '@vitejs/plugin-react@4.4.1(vite@6.3.5(@types/node@22.15.3)(sass@1.87.0))': 1275 | dependencies: 1276 | '@babel/core': 7.27.1 1277 | '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.27.1) 1278 | '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.27.1) 1279 | '@types/babel__core': 7.20.5 1280 | react-refresh: 0.17.0 1281 | vite: 6.3.5(@types/node@22.15.3)(sass@1.87.0) 1282 | transitivePeerDependencies: 1283 | - supports-color 1284 | 1285 | braces@3.0.3: 1286 | dependencies: 1287 | fill-range: 7.1.1 1288 | optional: true 1289 | 1290 | browserslist@4.24.5: 1291 | dependencies: 1292 | caniuse-lite: 1.0.30001717 1293 | electron-to-chromium: 1.5.149 1294 | node-releases: 2.0.19 1295 | update-browserslist-db: 1.1.3(browserslist@4.24.5) 1296 | 1297 | caniuse-lite@1.0.30001717: {} 1298 | 1299 | character-entities-legacy@1.1.4: {} 1300 | 1301 | character-entities@1.2.4: {} 1302 | 1303 | character-reference-invalid@1.1.4: {} 1304 | 1305 | chokidar@4.0.3: 1306 | dependencies: 1307 | readdirp: 4.1.2 1308 | 1309 | comma-separated-tokens@1.0.8: {} 1310 | 1311 | convert-source-map@2.0.0: {} 1312 | 1313 | cookie@1.0.2: {} 1314 | 1315 | csstype@3.1.3: {} 1316 | 1317 | debug@4.4.0: 1318 | dependencies: 1319 | ms: 2.1.3 1320 | 1321 | detect-libc@1.0.3: 1322 | optional: true 1323 | 1324 | electron-to-chromium@1.5.149: {} 1325 | 1326 | esbuild@0.25.3: 1327 | optionalDependencies: 1328 | '@esbuild/aix-ppc64': 0.25.3 1329 | '@esbuild/android-arm': 0.25.3 1330 | '@esbuild/android-arm64': 0.25.3 1331 | '@esbuild/android-x64': 0.25.3 1332 | '@esbuild/darwin-arm64': 0.25.3 1333 | '@esbuild/darwin-x64': 0.25.3 1334 | '@esbuild/freebsd-arm64': 0.25.3 1335 | '@esbuild/freebsd-x64': 0.25.3 1336 | '@esbuild/linux-arm': 0.25.3 1337 | '@esbuild/linux-arm64': 0.25.3 1338 | '@esbuild/linux-ia32': 0.25.3 1339 | '@esbuild/linux-loong64': 0.25.3 1340 | '@esbuild/linux-mips64el': 0.25.3 1341 | '@esbuild/linux-ppc64': 0.25.3 1342 | '@esbuild/linux-riscv64': 0.25.3 1343 | '@esbuild/linux-s390x': 0.25.3 1344 | '@esbuild/linux-x64': 0.25.3 1345 | '@esbuild/netbsd-arm64': 0.25.3 1346 | '@esbuild/netbsd-x64': 0.25.3 1347 | '@esbuild/openbsd-arm64': 0.25.3 1348 | '@esbuild/openbsd-x64': 0.25.3 1349 | '@esbuild/sunos-x64': 0.25.3 1350 | '@esbuild/win32-arm64': 0.25.3 1351 | '@esbuild/win32-ia32': 0.25.3 1352 | '@esbuild/win32-x64': 0.25.3 1353 | 1354 | escalade@3.2.0: {} 1355 | 1356 | fault@1.0.4: 1357 | dependencies: 1358 | format: 0.2.2 1359 | 1360 | fdir@6.4.4(picomatch@4.0.2): 1361 | optionalDependencies: 1362 | picomatch: 4.0.2 1363 | 1364 | fill-range@7.1.1: 1365 | dependencies: 1366 | to-regex-range: 5.0.1 1367 | optional: true 1368 | 1369 | format@0.2.2: {} 1370 | 1371 | fsevents@2.3.3: 1372 | optional: true 1373 | 1374 | gensync@1.0.0-beta.2: {} 1375 | 1376 | github-buttons@2.27.0: {} 1377 | 1378 | globals@11.12.0: {} 1379 | 1380 | hast-util-parse-selector@2.2.5: {} 1381 | 1382 | hastscript@6.0.0: 1383 | dependencies: 1384 | '@types/hast': 2.3.10 1385 | comma-separated-tokens: 1.0.8 1386 | hast-util-parse-selector: 2.2.5 1387 | property-information: 5.6.0 1388 | space-separated-tokens: 1.1.5 1389 | 1390 | highlight.js@10.7.3: {} 1391 | 1392 | highlightjs-vue@1.0.0: {} 1393 | 1394 | immutable@5.1.1: {} 1395 | 1396 | is-alphabetical@1.0.4: {} 1397 | 1398 | is-alphanumerical@1.0.4: 1399 | dependencies: 1400 | is-alphabetical: 1.0.4 1401 | is-decimal: 1.0.4 1402 | 1403 | is-decimal@1.0.4: {} 1404 | 1405 | is-extglob@2.1.1: 1406 | optional: true 1407 | 1408 | is-glob@4.0.3: 1409 | dependencies: 1410 | is-extglob: 2.1.1 1411 | optional: true 1412 | 1413 | is-hexadecimal@1.0.4: {} 1414 | 1415 | is-number@7.0.0: 1416 | optional: true 1417 | 1418 | js-tokens@4.0.0: {} 1419 | 1420 | jsesc@3.1.0: {} 1421 | 1422 | json5@2.2.3: {} 1423 | 1424 | lowlight@1.20.0: 1425 | dependencies: 1426 | fault: 1.0.4 1427 | highlight.js: 10.7.3 1428 | 1429 | lru-cache@5.1.1: 1430 | dependencies: 1431 | yallist: 3.1.1 1432 | 1433 | micromatch@4.0.8: 1434 | dependencies: 1435 | braces: 3.0.3 1436 | picomatch: 2.3.1 1437 | optional: true 1438 | 1439 | ms@2.1.3: {} 1440 | 1441 | nanoid@3.3.11: {} 1442 | 1443 | node-addon-api@7.1.1: 1444 | optional: true 1445 | 1446 | node-releases@2.0.19: {} 1447 | 1448 | parse-entities@2.0.0: 1449 | dependencies: 1450 | character-entities: 1.2.4 1451 | character-entities-legacy: 1.1.4 1452 | character-reference-invalid: 1.1.4 1453 | is-alphanumerical: 1.0.4 1454 | is-decimal: 1.0.4 1455 | is-hexadecimal: 1.0.4 1456 | 1457 | picocolors@1.1.1: {} 1458 | 1459 | picomatch@2.3.1: 1460 | optional: true 1461 | 1462 | picomatch@4.0.2: {} 1463 | 1464 | postcss@8.5.3: 1465 | dependencies: 1466 | nanoid: 3.3.11 1467 | picocolors: 1.1.1 1468 | source-map-js: 1.2.1 1469 | 1470 | prismjs@1.27.0: {} 1471 | 1472 | prismjs@1.29.0: {} 1473 | 1474 | property-information@5.6.0: 1475 | dependencies: 1476 | xtend: 4.0.2 1477 | 1478 | react-dom@19.1.0(react@19.1.0): 1479 | dependencies: 1480 | react: 19.1.0 1481 | scheduler: 0.26.0 1482 | 1483 | react-error-boundary@6.0.0(react@19.1.0): 1484 | dependencies: 1485 | '@babel/runtime': 7.27.1 1486 | react: 19.1.0 1487 | 1488 | react-github-btn@1.4.0(react@19.1.0): 1489 | dependencies: 1490 | github-buttons: 2.27.0 1491 | react: 19.1.0 1492 | 1493 | react-refresh@0.17.0: {} 1494 | 1495 | react-router@7.5.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0): 1496 | dependencies: 1497 | cookie: 1.0.2 1498 | react: 19.1.0 1499 | set-cookie-parser: 2.7.1 1500 | turbo-stream: 2.4.0 1501 | optionalDependencies: 1502 | react-dom: 19.1.0(react@19.1.0) 1503 | 1504 | react-syntax-highlighter@15.6.1(react@19.1.0): 1505 | dependencies: 1506 | '@babel/runtime': 7.25.7 1507 | highlight.js: 10.7.3 1508 | highlightjs-vue: 1.0.0 1509 | lowlight: 1.20.0 1510 | prismjs: 1.29.0 1511 | react: 19.1.0 1512 | refractor: 3.6.0 1513 | 1514 | react@19.1.0: {} 1515 | 1516 | readdirp@4.1.2: {} 1517 | 1518 | refractor@3.6.0: 1519 | dependencies: 1520 | hastscript: 6.0.0 1521 | parse-entities: 2.0.0 1522 | prismjs: 1.27.0 1523 | 1524 | regenerator-runtime@0.14.1: {} 1525 | 1526 | rollup@4.40.1: 1527 | dependencies: 1528 | '@types/estree': 1.0.7 1529 | optionalDependencies: 1530 | '@rollup/rollup-android-arm-eabi': 4.40.1 1531 | '@rollup/rollup-android-arm64': 4.40.1 1532 | '@rollup/rollup-darwin-arm64': 4.40.1 1533 | '@rollup/rollup-darwin-x64': 4.40.1 1534 | '@rollup/rollup-freebsd-arm64': 4.40.1 1535 | '@rollup/rollup-freebsd-x64': 4.40.1 1536 | '@rollup/rollup-linux-arm-gnueabihf': 4.40.1 1537 | '@rollup/rollup-linux-arm-musleabihf': 4.40.1 1538 | '@rollup/rollup-linux-arm64-gnu': 4.40.1 1539 | '@rollup/rollup-linux-arm64-musl': 4.40.1 1540 | '@rollup/rollup-linux-loongarch64-gnu': 4.40.1 1541 | '@rollup/rollup-linux-powerpc64le-gnu': 4.40.1 1542 | '@rollup/rollup-linux-riscv64-gnu': 4.40.1 1543 | '@rollup/rollup-linux-riscv64-musl': 4.40.1 1544 | '@rollup/rollup-linux-s390x-gnu': 4.40.1 1545 | '@rollup/rollup-linux-x64-gnu': 4.40.1 1546 | '@rollup/rollup-linux-x64-musl': 4.40.1 1547 | '@rollup/rollup-win32-arm64-msvc': 4.40.1 1548 | '@rollup/rollup-win32-ia32-msvc': 4.40.1 1549 | '@rollup/rollup-win32-x64-msvc': 4.40.1 1550 | fsevents: 2.3.3 1551 | 1552 | sass@1.87.0: 1553 | dependencies: 1554 | chokidar: 4.0.3 1555 | immutable: 5.1.1 1556 | source-map-js: 1.2.1 1557 | optionalDependencies: 1558 | '@parcel/watcher': 2.5.1 1559 | 1560 | scheduler@0.26.0: {} 1561 | 1562 | semver@6.3.1: {} 1563 | 1564 | set-cookie-parser@2.7.1: {} 1565 | 1566 | source-map-js@1.2.1: {} 1567 | 1568 | space-separated-tokens@1.1.5: {} 1569 | 1570 | tinyglobby@0.2.13: 1571 | dependencies: 1572 | fdir: 6.4.4(picomatch@4.0.2) 1573 | picomatch: 4.0.2 1574 | 1575 | to-regex-range@5.0.1: 1576 | dependencies: 1577 | is-number: 7.0.0 1578 | optional: true 1579 | 1580 | turbo-stream@2.4.0: {} 1581 | 1582 | typescript@5.8.3: {} 1583 | 1584 | undici-types@6.21.0: {} 1585 | 1586 | update-browserslist-db@1.1.3(browserslist@4.24.5): 1587 | dependencies: 1588 | browserslist: 4.24.5 1589 | escalade: 3.2.0 1590 | picocolors: 1.1.1 1591 | 1592 | vite@6.3.5(@types/node@22.15.3)(sass@1.87.0): 1593 | dependencies: 1594 | esbuild: 0.25.3 1595 | fdir: 6.4.4(picomatch@4.0.2) 1596 | picomatch: 4.0.2 1597 | postcss: 8.5.3 1598 | rollup: 4.40.1 1599 | tinyglobby: 0.2.13 1600 | optionalDependencies: 1601 | '@types/node': 22.15.3 1602 | fsevents: 2.3.3 1603 | sass: 1.87.0 1604 | 1605 | xtend@4.0.2: {} 1606 | 1607 | yallist@3.1.1: {} 1608 | -------------------------------------------------------------------------------- /example/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grubersjoe/react-github-calendar/3a547ae5e48a23e13615633c0b285386f1550a25/example/public/favicon.ico -------------------------------------------------------------------------------- /example/src/components/CodeBlock.tsx: -------------------------------------------------------------------------------- 1 | import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' 2 | import { tomorrow as theme } from 'react-syntax-highlighter/dist/esm/styles/prism' 3 | 4 | type Props = { 5 | children: string 6 | } 7 | 8 | const CodeBlock = ({ children }: Props) => ( 9 | 22 | {children} 23 | 24 | ) 25 | 26 | export default CodeBlock 27 | -------------------------------------------------------------------------------- /example/src/components/Docs.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState, type FormEventHandler } from 'react' 2 | import { ErrorBoundary } from 'react-error-boundary' 3 | import GitHubButton from 'react-github-btn' 4 | import GitHubCalendar, { type Props } from 'react-github-calendar' 5 | import { useSearchParams } from 'react-router' 6 | import CodeBlock from './CodeBlock' 7 | import { errorRenderer } from './Error' 8 | import '../styles.scss' 9 | import ForkMe from './ForkMe' 10 | 11 | const defaultUsername = 'grubersjoe' 12 | 13 | const Docs = () => { 14 | const [searchParams, setSearchParams] = useSearchParams() 15 | const initialUsername = searchParams.get('user') ?? defaultUsername 16 | 17 | const [username, setUsername] = useState(initialUsername) 18 | const [input, setInput] = useState(initialUsername) 19 | 20 | useEffect(() => { 21 | if (initialUsername !== username) { 22 | setUsername(initialUsername) 23 | setInput(initialUsername) 24 | } 25 | }, [initialUsername, username]) 26 | 27 | const onUsernameSubmit: FormEventHandler = event => { 28 | event.preventDefault() 29 | const val = input.trim() 30 | if (val && val !== username) { 31 | setSearchParams({ user: val.toLowerCase() }) 32 | } 33 | } 34 | 35 | return ( 36 |
37 |
38 | 39 |
40 |

GitHub Contributions Calendar

41 |
A React component to display a GitHub contributions calendar
42 |
43 | { 48 | setInput(event.target.value) 49 | }} 50 | autoComplete="on" 51 | required 52 | /> 53 | 54 |
55 |
56 |
57 | 58 |
59 |
60 |

61 | 62 | @{username} 63 | {' '} 64 | on GitHub 65 |

66 | 67 | 68 | 69 | 70 | 71 |

72 | Made with love by @grubersjoe. 73 |

74 | 75 |
76 | 77 | npm version 82 | 83 | 91 | Star 92 | 93 |
94 |
95 | 96 |
97 |

Installation

98 | npm add react-github-calendar 99 |

Then in your code:

100 | 101 | {`import GitHubCalendar from 'react-github-calendar'; 102 | 103 | `} 104 | 105 |
106 | 107 |
108 |

Component properties

109 |

110 | The component uses{' '} 111 | 112 | react-activity-calendar 113 | {' '} 114 | internally, so all its properties are supported. See the{' '} 115 | 116 | documentation 117 | 118 | . 119 |

120 |
121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 168 | 169 | 170 | 171 | 172 | 177 | 178 | 179 | 180 | 191 | 192 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 269 | 278 | 279 | 280 | 281 | 293 | 302 | 303 | 304 | 305 | 306 | 307 | 312 | 313 | 314 | 315 | 316 | 318 | 319 | 320 | 321 | 326 | 327 | 346 | 347 | 348 | 349 | 350 | 351 | 359 | 360 | 361 | 362 | 363 | 368 | 369 | 370 | 371 | 384 | 390 | 391 | 392 | 393 | 394 | 395 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 |
PropTypeDefaultDescription
usernamestring! 135 | 136 | A GitHub username (required, obviously). 137 |
yearnumber | 'last''last'To be rendered year. Defaults to the last year like on GitHub.
blockMarginnumber4Margin between blocks in pixels.
blockRadiusnumber2Border radius of blocks in pixels.
blockSizenumber12Block size in pixels.
colorScheme'light' | 'dark' 167 | Use a specific color scheme instead of the system one.
errorMessagestring 173 | 174 | Message to show if fetching GitHub contribution data fails. Only relevant if{' '} 175 | throwOnError is false. 176 |
eventHandlers 181 | (event: React.SyntheticEvent) 182 |
183 |   {'=>'} (data:{' '} 184 | 185 | Activity 186 | 187 | ) 188 |
189 |   {'=>'} void 190 |
{} 193 | Event handlers to register for the SVG{' '} 194 | 195 | {'<'}rect{'>'} 196 | {' '} 197 | elements that are used to render the calendar days. See this{' '} 198 | 199 | example 200 | 201 | . 202 |
fontSizenumber14Font size for text in pixels.
hideColorLegendbooleanfalseToggle to hide color legend below calendar.
hideMonthLabelsbooleanfalseToggle to hide month labels above calendar.
hideTotalCountbooleanfalseToggle to hide total count below calendar.
labelsLabels 232 | 233 | Localization strings for all calendar labels.{' '} 234 | 235 | See here for details 236 | 237 | . 238 |
loadingbooleanfalseToggle for loading state.
refReact.RefObject<HTMLElement>Ref to access the calendar DOM node.
renderBlock 255 | (
256 |   block:{' '} 257 | 258 | BlockElement 259 | 260 | , 261 |
262 |   activity:{' '} 263 | 264 | Activity 265 | 266 |
267 | ) {'=>'} ReactElement 268 |
270 | 271 | Render prop for calendar blocks (activities). For example, useful to wrap the 272 | element with a tooltip component. Use{' '} 273 | 274 | React.cloneElement 275 | {' '} 276 | to pass additional props to the element if necessary. 277 |
renderColorLegend 282 | (
283 |   block:{' '} 284 | 285 | BlockElement 286 | 287 | , 288 |
289 |   level: number 290 |
291 | ) {'=>'} ReactElement 292 |
294 | 295 | Render prop for color legend blocks. For example, useful to wrap the element 296 | with a tooltip component. Use{' '} 297 | 298 | React.cloneElement 299 | {' '} 300 | to pass additional props to the element if necessary. 301 |
showWeekdayLabelsboolean | Array<DayName>false 308 | Toggle to show weekday labels left to the calendar. Alternatively, pass a list 309 | of ISO 8601 weekday names to show. For example{' '} 310 | ['mon', 'wed', 'fri']. 311 |
styleReact.CSSProperties 317 | Style object to pass to component container.
theme 322 | 323 | ThemeInput 324 | 325 | GitHub theme 328 |

329 | Set the calendar colors for the light and dark{' '} 330 | system color scheme. The color scale for at least one color scheme needs to be 331 | specified. For undefined values, the default theme is selected. By default, 332 | the calendar will use the currently set system color scheme, but you can 333 | enforce a specific color scheme with the colorScheme prop. 334 |

335 |

336 | Define each color scale explicitly with five colors or pass exactly two colors 337 | (lowest and highest intensity) to calculate a single-hue scale. Colors can be 338 | specified in any valid CSS format. 339 |

340 |

341 | 342 | See this example 343 | 344 |

345 |
throwOnErrorbooleanfalse 352 | Whether to throw an Error if fetching GitHub contribution data 353 | fails. Use a React{' '} 354 | 355 | error boundary 356 | {' '} 357 | to handle the error. 358 |
totalCountnumber 364 | 365 | Overwrite the total activity count. Useful in combination with{' '} 366 | transformData. 367 |
transformData 372 | (data:{' '} 373 | 374 | Activity 375 | 376 | []) 377 |
378 |   {'=>'}{' '} 379 | 380 | Activity 381 | 382 | [] 383 |
385 | 386 | A function that receives the array of contribution data and that has to return 387 | an array with the same data type. See{' '} 388 | example. 389 |
transformTotalCountbooleantrue 396 | When the transformData property is set, the total contribution 397 | count will be calculated based on the transformed data. Set this to{' '} 398 | false to use the original contribution count for all data. 399 |
weekStartnumber0 (Sunday)Index of day to be used as start of week. 0 represents Sunday.
409 |
410 |
411 | 412 |
413 |

Examples & FAQ

414 |

415 | Please refer to the Storybook of the calendar component for{' '} 416 | interactive examples. 417 |

418 | 419 |

How do I add tooltips?

420 |

421 | See{' '} 422 | 423 | tooltip examples 424 | {' '} 425 | how to use the renderBlock prop. 426 |

427 | 428 |

Usage of the transformData prop

429 |

430 | You can pass a function as the transformData prop that receives the array 431 | of contribution data to manipulate it. The transformation function must meet the 432 | following signature: 433 |

434 | 435 | {`interface Activity { 436 | date: string; 437 | count: number; 438 | level: 0 | 1 | 2 | 3 | 4; 439 | } 440 | 441 | function transformData(data: Array): Array;`} 442 | 443 |

444 | For example, to only show the the contribution data of the last six months you can do 445 | the following: 446 |

447 | 448 | {`const selectLastHalfYear = contributions => { 449 | const currentYear = new Date().getFullYear(); 450 | const currentMonth = new Date().getMonth(); 451 | const shownMonths = 6; 452 | 453 | return contributions.filter(activity => { 454 | const date = new Date(activity.date); 455 | const monthOfDay = date.getMonth(); 456 | 457 | return ( 458 | date.getFullYear() === currentYear && 459 | monthOfDay > currentMonth - shownMonths && 460 | monthOfDay <= currentMonth 461 | ); 462 | }); 463 | }; 464 | 465 | // ... 466 | 467 | `} 475 | 476 | 477 |
478 | 479 | 480 | 490 | 491 | 492 |

493 | The total count will be recalculated based on the transformed data. However, you can 494 | enforce that the total count of the untransformed data is shown by setting the{' '} 495 | transformTotalCount to false. The text of total count label 496 | below the calendar can be adjusted using the labels.totalCount prop and the{' '} 497 | {{ count }} placeholder. 498 |

499 |
500 | 501 |

502 | 509 |

510 |
511 |
512 | ) 513 | } 514 | 515 | const selectLastHalfYear: Props['transformData'] = contributions => { 516 | const currentYear = new Date().getFullYear() 517 | const currentMonth = new Date().getMonth() 518 | const shownMonths = 6 519 | 520 | return contributions.filter(activity => { 521 | const date = new Date(activity.date) 522 | const monthOfDay = date.getMonth() 523 | 524 | return ( 525 | date.getFullYear() === currentYear && 526 | monthOfDay > currentMonth - shownMonths && 527 | monthOfDay <= currentMonth 528 | ) 529 | }) 530 | } 531 | 532 | export default Docs 533 | -------------------------------------------------------------------------------- /example/src/components/Error.tsx: -------------------------------------------------------------------------------- 1 | import type { FallbackProps } from 'react-error-boundary' 2 | 3 | export const errorRenderer = ({ error }: FallbackProps) => ( 4 |
5 | Error 6 | {error instanceof Error ? ( 7 | <> 8 |
9 | {error.message} 10 | 11 | ) : null} 12 |
13 | ) 14 | -------------------------------------------------------------------------------- /example/src/components/ForkMe.tsx: -------------------------------------------------------------------------------- 1 | import type { CSSProperties } from 'react' 2 | 3 | const style: CSSProperties = { 4 | position: 'absolute', 5 | top: 0, 6 | right: 0, 7 | border: 0, 8 | fill: 'currentcolor', 9 | } 10 | 11 | const ForkMe = () => ( 12 | 17 | 29 | 30 | ) 31 | 32 | export default ForkMe 33 | -------------------------------------------------------------------------------- /example/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import { createHashRouter } from 'react-router' 4 | import { RouterProvider } from 'react-router/dom' 5 | import Docs from './components/Docs' 6 | 7 | const container = document.getElementById('root') 8 | 9 | if (!container) { 10 | throw Error('#root not found') 11 | } 12 | 13 | const root = createRoot(container) 14 | 15 | const router = createHashRouter([ 16 | { 17 | path: '/*', 18 | element: , 19 | }, 20 | ]) 21 | 22 | root.render( 23 | 24 | 25 | , 26 | ) 27 | -------------------------------------------------------------------------------- /example/src/styles.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --font-default: 3 | -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', 4 | sans-serif; 5 | --font-mono: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace; 6 | --color-text: #1b1b1b; 7 | --color-border: hsl(0, 0%, 88%); 8 | --color-border-active: hsl(0, 0%, 80%); 9 | --color-page-bg: #fff; 10 | --color-header-bg: #141414; 11 | --color-header-text: var(--color-page-bg); 12 | --color-code-bg: hsl(0, 0%, 94%); 13 | --color-focus: hsl(136, 82%, 40%); 14 | --font-size-code: 0.9rem; 15 | } 16 | 17 | @media (prefers-color-scheme: dark) { 18 | :root { 19 | --color-text: #fff; 20 | --color-border: hsl(0, 0%, 24%); 21 | --color-border-active: hsl(0, 0%, 32%); 22 | --color-page-bg: hsl(216, 28%, 7%); 23 | --color-header-bg: #eee; 24 | --color-code-bg: hsl(0, 0%, 18%); 25 | } 26 | } 27 | 28 | @media (min-width: 768px) { 29 | :root { 30 | --font-size-code: 0.8rem; 31 | } 32 | } 33 | 34 | * { 35 | box-sizing: border-box; 36 | } 37 | 38 | :focus-visible { 39 | outline: var(--color-focus) auto 1px; 40 | } 41 | 42 | button::-moz-focus-inner { 43 | border: 0; 44 | } 45 | 46 | html { 47 | font-family: var(--font-default); 48 | font-size: 16px; 49 | line-height: 1.5; 50 | color: var(--color-text); 51 | background-color: var(--color-page-bg); 52 | 53 | @media (min-width: 768px) { 54 | font-size: 18px; 55 | } 56 | } 57 | 58 | body { 59 | margin: 0; 60 | padding: 0; 61 | } 62 | 63 | header { 64 | padding: 1.5rem 0 1.25rem; 65 | background-color: var(--color-header-bg); 66 | color: var(--color-header-text); 67 | font-size: 1.1rem; 68 | line-height: 1.3; 69 | } 70 | 71 | header a { 72 | color: inherit; 73 | } 74 | 75 | header button { 76 | color: var(--color-text); 77 | background-color: var(--color-page-bg); 78 | } 79 | 80 | h1, 81 | h2, 82 | h3 { 83 | font-weight: 600; 84 | } 85 | 86 | h1 { 87 | margin: 0 0 0.5em; 88 | font-size: 1.953rem; 89 | 90 | @media (min-width: 768px) { 91 | font-size: 2.441rem; 92 | } 93 | } 94 | 95 | h2 { 96 | margin: 2.5rem 0 0.5em; 97 | font-size: 1.563rem; 98 | } 99 | 100 | h3 { 101 | margin: 2rem 0 0.5em; 102 | font-size: 1.25rem; 103 | } 104 | 105 | p, 106 | ul, 107 | ol, 108 | pre { 109 | max-width: 760px; 110 | } 111 | 112 | p { 113 | margin: 0 0 1.5rem; 114 | } 115 | 116 | li { 117 | margin-bottom: 0.75em; 118 | 119 | p { 120 | margin: 0 0 0.75rem; 121 | } 122 | 123 | pre { 124 | margin: 0 0 1rem; 125 | } 126 | } 127 | 128 | a { 129 | color: inherit; 130 | text-decoration: underline 2px var(--color-border); 131 | text-underline-offset: 3px; 132 | 133 | &:hover { 134 | text-decoration: underline 2px var(--color-border-active); 135 | } 136 | } 137 | 138 | section > :last-child { 139 | margin-bottom: 0; 140 | } 141 | 142 | hr { 143 | margin: 2.5rem 0; 144 | height: 3px; 145 | background-color: var(--color-border); 146 | border: 0; 147 | } 148 | 149 | pre, 150 | code { 151 | font-family: var(--font-mono); 152 | } 153 | 154 | code { 155 | background: var(--color-code-bg); 156 | font-size: var(--font-size-code); 157 | } 158 | 159 | pre code { 160 | background: inherit; 161 | border-radius: 0; 162 | padding: 0; 163 | } 164 | 165 | .token.known-class-name { 166 | text-decoration: none !important; 167 | } 168 | 169 | table { 170 | max-width: 100%; 171 | margin: 0; 172 | border-collapse: collapse; 173 | 174 | @media (min-width: 768px) { 175 | min-width: 540px; 176 | font-size: 0.9rem; 177 | } 178 | } 179 | 180 | .table-overflow { 181 | width: 100%; 182 | overflow: auto; 183 | } 184 | 185 | thead, 186 | tr { 187 | border-bottom: 2px solid var(--color-border); 188 | } 189 | 190 | tr { 191 | border-bottom: 1px solid var(--color-border); 192 | } 193 | 194 | th { 195 | font-weight: 600; 196 | text-align: left; 197 | } 198 | 199 | th, 200 | td { 201 | padding: 0.6rem 0; 202 | vertical-align: top; 203 | line-height: 1.4; 204 | } 205 | 206 | td:not(:last-of-type) { 207 | padding-right: 1.25rem; 208 | } 209 | 210 | td:not(:last-of-type) { 211 | font-family: var(--font-mono); 212 | font-size: var(--font-size-code); 213 | white-space: nowrap; 214 | 215 | @media (min-width: 768px) { 216 | font-size: 0.75rem; 217 | } 218 | } 219 | 220 | td p { 221 | margin-bottom: 1rem; 222 | } 223 | 224 | code { 225 | padding: 0.15em 0.4em; 226 | border-radius: 3px; 227 | } 228 | 229 | form { 230 | display: flex; 231 | flex-wrap: wrap; 232 | column-gap: 0.75rem; 233 | margin: 2rem 0 0; 234 | 235 | @media (min-width: 768px) { 236 | margin: 2.5rem 0 0; 237 | } 238 | 239 | & > * { 240 | flex: 0 0 100%; 241 | 242 | @media (min-width: 768px) { 243 | flex: 0 0 auto; 244 | } 245 | } 246 | } 247 | 248 | input, 249 | button { 250 | margin-bottom: 1rem; 251 | padding: 0.9rem; 252 | font-family: inherit; 253 | font-weight: normal; 254 | font-size: 0.9rem; 255 | border: none; 256 | border-radius: 4px; 257 | line-height: 1; 258 | 259 | @media (min-width: 768px) { 260 | margin-bottom: 0; 261 | padding: 0.75rem; 262 | } 263 | } 264 | 265 | input { 266 | min-width: 15em; 267 | background-color: #fff; 268 | 269 | &:invalid { 270 | box-shadow: none; 271 | } 272 | } 273 | 274 | button { 275 | cursor: pointer; 276 | color: var(--color-page-bg); 277 | background-color: var(--color-text); 278 | 279 | &:active { 280 | position: relative; 281 | top: 1px; 282 | left: 1px; 283 | } 284 | } 285 | 286 | .container { 287 | margin: 1.5rem auto; 288 | padding: 0 20px; 289 | 290 | @media (min-width: 768px) { 291 | width: calc(848px + 2rem); /* default calendar width */ 292 | margin: 2rem auto; 293 | } 294 | } 295 | 296 | .error { 297 | display: inline-block; 298 | margin: 0 0 1rem; 299 | padding: 0.5rem 0.75rem; 300 | background-color: #f8d7da; 301 | border: 1px solid #f1aeb5; 302 | border-radius: 4px; 303 | font-size: 90%; 304 | } 305 | 306 | .github-corner .octo { 307 | fill: var(--color-text); 308 | } 309 | 310 | .github-corner:hover .octo-arm { 311 | animation: octocat-wave 560ms ease-in-out; 312 | } 313 | 314 | @keyframes octocat-wave { 315 | 0%, 316 | 100% { 317 | transform: rotate(0); 318 | } 319 | 320 | 20%, 321 | 60% { 322 | transform: rotate(-25deg); 323 | } 324 | 325 | 40%, 326 | 80% { 327 | transform: rotate(10deg); 328 | } 329 | } 330 | 331 | @media (max-width: 500px) { 332 | .github-corner:hover .octo-arm { 333 | animation: none; 334 | } 335 | 336 | .github-corner .octo-arm { 337 | animation: octocat-wave 560ms ease-in-out; 338 | } 339 | } 340 | -------------------------------------------------------------------------------- /example/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /example/vite.config.mts: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react' 2 | import { defineConfig } from 'vite' 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | base: process.env.NODE_ENV === 'production' ? '/react-github-calendar/' : undefined, 7 | server: { 8 | port: 8080, 9 | host: true, 10 | }, 11 | optimizeDeps: { 12 | include: ['react-github-calendar'], 13 | }, 14 | build: { 15 | outDir: 'build', 16 | commonjsOptions: { 17 | include: [/react-github-calendar/], 18 | }, 19 | }, 20 | }) 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-github-calendar", 3 | "version": "4.5.7", 4 | "description": " React component to display a GitHub contributions calendar", 5 | "author": "Jonathan Gruber ", 6 | "license": "MIT", 7 | "homepage": "https://grubersjoe.github.io/react-github-calendar/", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/grubersjoe/react-github-calendar.git" 11 | }, 12 | "main": "build/index.js", 13 | "types": "build/index.d.ts", 14 | "scripts": { 15 | "build": "rollup -c", 16 | "check": "pnpx prettier -c . && pnpm exec tsc && pnpm lint", 17 | "deploy": "gh-pages -d example/build", 18 | "dev": "rollup -c -w", 19 | "format": "prettier --write .", 20 | "lint": "eslint .", 21 | "postbuild": "dts-bundle-generator src/index.tsx -o build/index.d.ts --no-check --no-banner", 22 | "predeploy": "pnpm build && cd example && pnpm install && pnpm build", 23 | "prepare": "husky", 24 | "prepublishOnly": "pnpm check && pnpm build" 25 | }, 26 | "dependencies": { 27 | "react-activity-calendar": "^2.7.11", 28 | "react-error-boundary": "^6.0.0" 29 | }, 30 | "devDependencies": { 31 | "@babel/core": "^7.27.1", 32 | "@babel/preset-env": "^7.27.1", 33 | "@babel/preset-react": "^7.27.1", 34 | "@babel/preset-typescript": "^7.27.1", 35 | "@eslint/js": "^9.26.0", 36 | "@ianvs/prettier-plugin-sort-imports": "^4.3.1", 37 | "@rollup/plugin-babel": "^6.0.3", 38 | "@rollup/plugin-node-resolve": "^16.0.0", 39 | "@types/node": "^22.13.9", 40 | "@types/react": "^19.0.10", 41 | "@types/tinycolor2": "^1.4.6", 42 | "dts-bundle-generator": "^9.5.1", 43 | "eslint": "^9.26.0", 44 | "eslint-plugin-react": "^7.37.3", 45 | "eslint-plugin-react-hooks": "^5.2.0", 46 | "gh-pages": "^6.3.0", 47 | "globals": "^16.0.0", 48 | "husky": "^9.1.7", 49 | "postcss": "^8.5.3", 50 | "prettier": "^3.5.3", 51 | "react": "^19.0.0", 52 | "rollup": "^4.34.9", 53 | "rollup-plugin-filesize": "^10.0.0", 54 | "rollup-plugin-peer-deps-external": "^2.2.2", 55 | "rollup-plugin-postcss": "^4.0.2", 56 | "typescript": "^5.8.2", 57 | "typescript-eslint": "^8.26.0" 58 | }, 59 | "peerDependencies": { 60 | "react": "^18.0.0 || ^19.0.0" 61 | }, 62 | "pnpm": { 63 | "overrides": { 64 | "react": "^19", 65 | "@types/react": "^19" 66 | } 67 | }, 68 | "files": [ 69 | "build" 70 | ], 71 | "browserslist": [ 72 | "last 2 chrome version", 73 | "last 2 firefox version", 74 | "last 2 safari version" 75 | ] 76 | } 77 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grubersjoe/react-github-calendar/3a547ae5e48a23e13615633c0b285386f1550a25/preview.png -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import babel from '@rollup/plugin-babel' 2 | import resolve from '@rollup/plugin-node-resolve' 3 | import filesize from 'rollup-plugin-filesize' 4 | import external from 'rollup-plugin-peer-deps-external' 5 | import postcss from 'rollup-plugin-postcss' 6 | import pkg from './package.json' with { type: 'json' } 7 | 8 | const extensions = ['.ts', '.tsx'] 9 | 10 | export default { 11 | input: 'src/index.tsx', 12 | output: { 13 | file: pkg.main, 14 | format: 'cjs', 15 | sourcemap: true, 16 | exports: 'named', 17 | // Use 'auto' instead of 'default' for better interoperability with CRA etc. 18 | // https://rollupjs.org/guide/en/#outputinterop 19 | interop: 'auto', 20 | // Rollup does not support this React Server Components directive yet. 21 | // https://github.com/rollup/rollup/issues/4699 22 | banner: `'use client';`, 23 | }, 24 | plugins: [ 25 | external({ 26 | includeDependencies: true, 27 | }), 28 | postcss({ 29 | modules: true, 30 | }), 31 | babel({ 32 | extensions, 33 | babelHelpers: 'bundled', 34 | }), 35 | resolve({ 36 | extensions, 37 | }), 38 | filesize(), 39 | ], 40 | onwarn(warning, warn) { 41 | if (warning.code === 'MODULE_LEVEL_DIRECTIVE' && warning.message.includes('use client')) { 42 | return // ignore the error for now 43 | } 44 | warn(warning) 45 | }, 46 | } 47 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { forwardRef, useCallback, useEffect, useState } from 'react' 4 | import Calendar, { 5 | Skeleton, 6 | type Props as ActivityCalendarProps, 7 | type ThemeInput, 8 | } from 'react-activity-calendar' 9 | import { transformData } from './lib' 10 | import type { Activity, ApiErrorResponse, ApiResponse, Year } from './types' 11 | 12 | export type Props = { 13 | username: string 14 | errorMessage?: string 15 | throwOnError?: boolean 16 | transformData?: (data: Array) => Array 17 | transformTotalCount?: boolean 18 | year?: Year 19 | } & Omit 20 | 21 | async function fetchCalendarData(username: string, year: Year): Promise { 22 | const apiUrl = 'https://github-contributions-api.jogruber.de/v4/' 23 | const response = await fetch(`${apiUrl}${username}?y=${String(year)}`) 24 | const data = (await response.json()) as ApiResponse | ApiErrorResponse 25 | 26 | if (!response.ok) { 27 | throw Error( 28 | `Fetching GitHub contribution data for "${username}" failed: ${(data as ApiErrorResponse).error}`, 29 | ) 30 | } 31 | 32 | return data as ApiResponse 33 | } 34 | 35 | const GitHubCalendar = forwardRef( 36 | ( 37 | { 38 | username, 39 | year = 'last', 40 | labels, 41 | transformData: transformFn, 42 | transformTotalCount = true, 43 | throwOnError = false, 44 | errorMessage = `Error – Fetching GitHub contribution data for "${username}" failed.`, 45 | ...props 46 | }, 47 | ref, 48 | ) => { 49 | const [data, setData] = useState(null) 50 | const [loading, setLoading] = useState(false) 51 | const [error, setError] = useState(null) 52 | 53 | const fetchData = useCallback(() => { 54 | setLoading(true) 55 | setError(null) 56 | fetchCalendarData(username, year) 57 | .then(setData) 58 | .catch((err: unknown) => { 59 | if (err instanceof Error) { 60 | setError(err) 61 | } 62 | }) 63 | .finally(() => { 64 | setLoading(false) 65 | }) 66 | }, [username, year]) 67 | 68 | useEffect(fetchData, [fetchData]) 69 | 70 | // React error boundaries can't handle asynchronous code, so rethrow. 71 | if (error) { 72 | if (throwOnError) { 73 | throw error 74 | } else { 75 | return
{errorMessage}
76 | } 77 | } 78 | 79 | if (loading || !data) { 80 | return 81 | } 82 | 83 | const theme = props.theme ?? gitHubTheme 84 | 85 | const defaultLabels = { 86 | totalCount: `{{count}} contributions in ${year === 'last' ? 'the last year' : '{{year}}'}`, 87 | } 88 | 89 | const totalCount = year === 'last' ? data.total.lastYear : data.total[year] 90 | 91 | return ( 92 | 102 | ) 103 | }, 104 | ) 105 | 106 | GitHubCalendar.displayName = 'GitHubCalendar' 107 | 108 | const gitHubTheme = { 109 | light: ['#ebedf0', '#9be9a8', '#40c463', '#30a14e', '#216e39'], 110 | dark: ['#161b22', '#0e4429', '#006d32', '#26a641', '#39d353'], 111 | } satisfies ThemeInput 112 | 113 | export default GitHubCalendar 114 | -------------------------------------------------------------------------------- /src/lib.ts: -------------------------------------------------------------------------------- 1 | import type { Activity } from './types' 2 | 3 | export const transformData = ( 4 | data: Array, 5 | transformFn?: (data: Array) => Array, 6 | ): Array => { 7 | if (typeof transformFn !== 'function') { 8 | return data 9 | } 10 | 11 | const transformedData = transformFn(data) 12 | 13 | if (!Array.isArray(transformedData)) { 14 | throw Error(`transformData() function must return a list of Activity objects.`) 15 | } 16 | 17 | for (const d of transformedData) { 18 | if (!isRecord(d)) { 19 | throw Error(`transformData() must return a list of valid Activity objects.`) 20 | } 21 | 22 | if (typeof d.count !== 'number' || d.count < 0) { 23 | throw Error(`Required property "count: number" missing or invalid. Got: ${d.count as string}`) 24 | } 25 | 26 | if (typeof d.date !== 'string' || !/\d{4}-\d{2}-\d{2}/.test(d.date)) { 27 | throw Error( 28 | `Required property "date: YYYY-MM-DD" missing or invalid. Got: ${d.date as string}`, 29 | ) 30 | } 31 | 32 | if (typeof d.level !== 'number' || d.level < 0 || d.level > 4) { 33 | throw Error( 34 | `Required property "level: 0 | 1 | 2 | 3 | 4" missing or invalid: Got: ${d.level as string}.`, 35 | ) 36 | } 37 | } 38 | 39 | return transformedData as Array 40 | } 41 | 42 | const isRecord = (o: unknown): o is Record => 43 | Object.prototype.toString.call(o) === '[object Object]' 44 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export type Activity = { 2 | date: string 3 | count: number 4 | level: 0 | 1 | 2 | 3 | 4 5 | } 6 | 7 | export type Year = number | 'last' 8 | 9 | export type ApiResponse = { 10 | total: { 11 | [year: number]: number 12 | [year: string]: number // 'lastYear; 13 | } 14 | contributions: Array 15 | } 16 | 17 | export type ApiErrorResponse = { 18 | error: string 19 | } 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src/**/*", "example/**/*", "./*"], 3 | "exclude": ["**/build/"], 4 | "compilerOptions": { 5 | "allowJs": true, 6 | "esModuleInterop": true, 7 | "isolatedModules": true, 8 | "jsx": "preserve", 9 | "lib": ["es2022", "dom", "dom.iterable"], 10 | "module": "preserve", 11 | "moduleDetection": "force", 12 | "noEmit": true, 13 | "noImplicitOverride": true, 14 | "noUncheckedIndexedAccess": true, 15 | "resolveJsonModule": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "target": "es2022", 19 | "verbatimModuleSyntax": true 20 | } 21 | } 22 | --------------------------------------------------------------------------------