Compare changes

Choose any two refs to compare.

-4
.vscode/extensions.json
···
-
{
-
"recommendations": ["astro-build.astro-vscode"],
-
"unwantedRecommendations": []
-
}
-11
.vscode/launch.json
···
-
{
-
"version": "0.2.0",
-
"configurations": [
-
{
-
"command": "./node_modules/.bin/astro dev",
-
"name": "Development server",
-
"request": "launch",
-
"type": "node-terminal"
-
}
-
]
-
}
-46
README.md
···
-
# Astro Starter Kit: Basics
-
-
```sh
-
bun create astro@latest -- --template basics
-
```
-
-
> ๐Ÿง‘โ€๐Ÿš€ **Seasoned astronaut?** Delete this file. Have fun!
-
-
## ๐Ÿš€ Project Structure
-
-
Inside of your Astro project, you'll see the following folders and files:
-
-
```text
-
/
-
โ”œโ”€โ”€ public/
-
โ”‚ โ””โ”€โ”€ favicon.svg
-
โ”œโ”€โ”€ src
-
โ”‚ย ย  โ”œโ”€โ”€ assets
-
โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ astro.svg
-
โ”‚ย ย  โ”œโ”€โ”€ components
-
โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ Welcome.astro
-
โ”‚ย ย  โ”œโ”€โ”€ layouts
-
โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ Layout.astro
-
โ”‚ย ย  โ””โ”€โ”€ pages
-
โ”‚ย ย  โ””โ”€โ”€ index.astro
-
โ””โ”€โ”€ package.json
-
```
-
-
To learn more about the folder structure of an Astro project, refer to [our guide on project structure](https://docs.astro.build/en/basics/project-structure/).
-
-
## ๐Ÿงž Commands
-
-
All commands are run from the root of the project, from a terminal:
-
-
| Command | Action |
-
| :------------------------ | :----------------------------------------------- |
-
| `bun install` | Installs dependencies |
-
| `bun dev` | Starts local dev server at `localhost:4321` |
-
| `bun build` | Build your production site to `./dist/` |
-
| `bun preview` | Preview your build locally, before deploying |
-
| `bun astro ...` | Run CLI commands like `astro add`, `astro check` |
-
| `bun astro -- --help` | Get help using the Astro CLI |
-
-
## ๐Ÿ‘€ Want to learn more?
-
-
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
+5 -1
astro.config.mjs
···
import tailwindcss from '@tailwindcss/vite';
+
import react from '@astrojs/react';
+
// https://astro.build/config
export default defineConfig({
vite: {
plugins: [tailwindcss()]
-
}
+
},
+
+
integrations: [react()]
});
+102
bun.lock
···
"": {
"name": "mywebsite-2026",
"dependencies": {
+
"@astrojs/react": "^4.4.2",
"@lucide/astro": "^0.553.0",
"@lucide/lab": "^0.1.2",
"@tailwindcss/vite": "^4.1.17",
+
"@types/react": "^19.2.2",
+
"@types/react-dom": "^19.2.2",
"astro": "^5.15.4",
+
"react": "^19.2.0",
+
"react-dom": "^19.2.0",
+
"react-github-calendar": "^4.5.11",
"tailwindcss": "^4.1.17",
},
"devDependencies": {
···
"@astrojs/prism": ["@astrojs/prism@3.3.0", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="],
+
"@astrojs/react": ["@astrojs/react@4.4.2", "", { "dependencies": { "@vitejs/plugin-react": "^4.7.0", "ultrahtml": "^1.6.0", "vite": "^6.4.1" }, "peerDependencies": { "@types/react": "^17.0.50 || ^18.0.21 || ^19.0.0", "@types/react-dom": "^17.0.17 || ^18.0.6 || ^19.0.0", "react": "^17.0.2 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0" } }, "sha512-1tl95bpGfuaDMDn8O3x/5Dxii1HPvzjvpL2YTuqOOrQehs60I2DKiDgh1jrKc7G8lv+LQT5H15V6QONQ+9waeQ=="],
+
"@astrojs/telemetry": ["@astrojs/telemetry@3.3.0", "", { "dependencies": { "ci-info": "^4.2.0", "debug": "^4.4.0", "dlv": "^1.1.3", "dset": "^3.1.4", "is-docker": "^3.0.0", "is-wsl": "^3.1.0", "which-pm-runs": "^1.1.0" } }, "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ=="],
+
+
"@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
+
+
"@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="],
+
+
"@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="],
+
+
"@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="],
+
+
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="],
+
+
"@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="],
+
+
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="],
+
+
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="],
+
+
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="],
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
+
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
+
+
"@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="],
+
"@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="],
+
+
"@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="],
+
+
"@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],
+
+
"@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],
+
+
"@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="],
"@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="],
···
"@oslojs/encoding": ["@oslojs/encoding@1.1.0", "", {}, "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ=="],
+
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="],
+
"@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.52.5", "", { "os": "android", "cpu": "arm" }, "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ=="],
···
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.17", "", { "dependencies": { "@tailwindcss/node": "4.1.17", "@tailwindcss/oxide": "4.1.17", "tailwindcss": "4.1.17" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA=="],
+
"@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
+
+
"@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="],
+
+
"@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="],
+
+
"@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="],
+
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
···
"@types/node": ["@types/node@24.10.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A=="],
+
"@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="],
+
+
"@types/react-dom": ["@types/react-dom@19.2.2", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw=="],
+
"@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
+
+
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="],
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
···
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
+
"baseline-browser-mapping": ["baseline-browser-mapping@2.8.25", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-2NovHVesVF5TXefsGX1yzx1xgr7+m9JQenvz6FQY3qd+YXkKkYiv+vTCc7OriP9mcDZpTC5mAOYN4ocd29+erA=="],
+
"boxen": ["boxen@8.0.1", "", { "dependencies": { "ansi-align": "^3.0.1", "camelcase": "^8.0.0", "chalk": "^5.3.0", "cli-boxes": "^3.0.0", "string-width": "^7.2.0", "type-fest": "^4.21.0", "widest-line": "^5.0.0", "wrap-ansi": "^9.0.0" } }, "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw=="],
"brotli": ["brotli@1.3.3", "", { "dependencies": { "base64-js": "^1.1.2" } }, "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg=="],
+
+
"browserslist": ["browserslist@4.27.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", "electron-to-chromium": "^1.5.238", "node-releases": "^2.0.26", "update-browserslist-db": "^1.1.4" }, "bin": { "browserslist": "cli.js" } }, "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw=="],
"camelcase": ["camelcase@8.0.0", "", {}, "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA=="],
+
"caniuse-lite": ["caniuse-lite@1.0.30001754", "", {}, "sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg=="],
+
"ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
···
"common-ancestor-path": ["common-ancestor-path@1.0.1", "", {}, "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="],
+
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
+
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
"cookie-es": ["cookie-es@1.2.2", "", {}, "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg=="],
···
"cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
+
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
+
+
"date-fns": ["date-fns@4.1.0", "", {}, "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg=="],
+
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
"decode-named-character-reference": ["decode-named-character-reference@1.2.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q=="],
···
"dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="],
"dset": ["dset@3.1.4", "", {}, "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA=="],
+
+
"electron-to-chromium": ["electron-to-chromium@1.5.249", "", {}, "sha512-5vcfL3BBe++qZ5kuFhD/p8WOM1N9m3nwvJPULJx+4xf2usSlZFJ0qoNYO2fOX4hi3ocuDcmDobtA+5SFr4OmBg=="],
"emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
···
"esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
+
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
+
"escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
"estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
···
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
+
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
+
"get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="],
"github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
···
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
+
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
+
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
+
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
+
+
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
+
"kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
"lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
···
"node-mock-http": ["node-mock-http@1.0.3", "", {}, "sha512-jN8dK25fsfnMrVsEhluUTPkBFY+6ybu7jSB1n+ri/vOGjJxU8J9CZhpSGkHXSkFjtUhbmoncG/YG9ta5Ludqog=="],
+
"node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
+
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
"ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="],
···
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
"radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="],
+
+
"react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="],
+
+
"react-activity-calendar": ["react-activity-calendar@2.7.15", "", { "dependencies": { "date-fns": "^4.1.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0" } }, "sha512-sPO4tDJp+sRbV8F/LhUZ/woHmi4dg0Phd+Kt1Jw0orSfGfEqGCm7fFXiTIAvuuAwpwxqPEYEnfNzOLEfUrdg1A=="],
+
+
"react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="],
+
+
"react-github-calendar": ["react-github-calendar@4.5.11", "", { "dependencies": { "react-activity-calendar": "^2.7.15" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0" } }, "sha512-tDUjAIYILYtPmPUrA/KKuCcGY9A0PcRQEjnOGcAoqV2qeaibh3IQ+YznQOYr78PsBfLIVtq4nZYYM3QadjGu+Q=="],
+
+
"react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
···
"rollup": ["rollup@4.52.5", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.52.5", "@rollup/rollup-android-arm64": "4.52.5", "@rollup/rollup-darwin-arm64": "4.52.5", "@rollup/rollup-darwin-x64": "4.52.5", "@rollup/rollup-freebsd-arm64": "4.52.5", "@rollup/rollup-freebsd-x64": "4.52.5", "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", "@rollup/rollup-linux-arm-musleabihf": "4.52.5", "@rollup/rollup-linux-arm64-gnu": "4.52.5", "@rollup/rollup-linux-arm64-musl": "4.52.5", "@rollup/rollup-linux-loong64-gnu": "4.52.5", "@rollup/rollup-linux-ppc64-gnu": "4.52.5", "@rollup/rollup-linux-riscv64-gnu": "4.52.5", "@rollup/rollup-linux-riscv64-musl": "4.52.5", "@rollup/rollup-linux-s390x-gnu": "4.52.5", "@rollup/rollup-linux-x64-gnu": "4.52.5", "@rollup/rollup-linux-x64-musl": "4.52.5", "@rollup/rollup-openharmony-arm64": "4.52.5", "@rollup/rollup-win32-arm64-msvc": "4.52.5", "@rollup/rollup-win32-ia32-msvc": "4.52.5", "@rollup/rollup-win32-x64-gnu": "4.52.5", "@rollup/rollup-win32-x64-msvc": "4.52.5", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw=="],
+
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
+
"semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="],
···
"unstorage": ["unstorage@1.17.2", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.4", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.0", "ufo": "^1.6.1" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-cKEsD6iBWJgOMJ6vW1ID/SYuqNf8oN4yqRk8OYqaVQ3nnkJXOT1PSpaMh2QfzLs78UN5kSNRD2c/mgjT8tX7+w=="],
+
"update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="],
+
"vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
"vfile-location": ["vfile-location@5.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="],
···
"xxhash-wasm": ["xxhash-wasm@1.1.0", "", {}, "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA=="],
+
"yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
+
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
"yocto-queue": ["yocto-queue@1.2.1", "", {}, "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg=="],
···
"zod-to-ts": ["zod-to-ts@1.2.0", "", { "peerDependencies": { "typescript": "^4.9.4 || ^5.0.2", "zod": "^3" } }, "sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA=="],
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
+
+
"@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
+
+
"@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
+
+
"@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
+6
package.json
···
"astro": "astro"
},
"dependencies": {
+
"@astrojs/react": "^4.4.2",
"@lucide/astro": "^0.553.0",
"@lucide/lab": "^0.1.2",
"@tailwindcss/vite": "^4.1.17",
+
"@types/react": "^19.2.2",
+
"@types/react-dom": "^19.2.2",
"astro": "^5.15.4",
+
"react": "^19.2.0",
+
"react-dom": "^19.2.0",
+
"react-github-calendar": "^4.5.11",
"tailwindcss": "^4.1.17"
},
"devDependencies": {
public/banner.png

This is a binary file and will not be displayed.

public/celeste_exhale.mp3

This is a binary file and will not be displayed.

+1
public/pause.svg
···
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#bac2de" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-pause"><rect x="6" y="4" width="4" height="16"></rect><rect x="14" y="4" width="4" height="16"></rect></svg>
+1
public/play.svg
···
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#bac2de" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-play"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>
-1
src/assets/astro.svg
···
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" width="115" height="48"><path fill="#17191E" d="M7.77 36.35C6.4 35.11 6 32.51 6.57 30.62c.99 1.2 2.35 1.57 3.75 1.78 2.18.33 4.31.2 6.33-.78.23-.12.44-.27.7-.42.18.55.23 1.1.17 1.67a4.56 4.56 0 0 1-1.94 3.23c-.43.32-.9.61-1.34.91-1.38.94-1.76 2.03-1.24 3.62l.05.17a3.63 3.63 0 0 1-1.6-1.38 3.87 3.87 0 0 1-.63-2.1c0-.37 0-.74-.05-1.1-.13-.9-.55-1.3-1.33-1.32a1.56 1.56 0 0 0-1.63 1.26c0 .06-.03.12-.05.2Z"/><path fill="url(#a)" d="M7.77 36.35C6.4 35.11 6 32.51 6.57 30.62c.99 1.2 2.35 1.57 3.75 1.78 2.18.33 4.31.2 6.33-.78.23-.12.44-.27.7-.42.18.55.23 1.1.17 1.67a4.56 4.56 0 0 1-1.94 3.23c-.43.32-.9.61-1.34.91-1.38.94-1.76 2.03-1.24 3.62l.05.17a3.63 3.63 0 0 1-1.6-1.38 3.87 3.87 0 0 1-.63-2.1c0-.37 0-.74-.05-1.1-.13-.9-.55-1.3-1.33-1.32a1.56 1.56 0 0 0-1.63 1.26c0 .06-.03.12-.05.2Z"/><path fill="#17191E" d="M.02 30.31s4.02-1.95 8.05-1.95l3.04-9.4c.11-.45.44-.76.82-.76.37 0 .7.31.82.76l3.04 9.4c4.77 0 8.05 1.95 8.05 1.95L17 11.71c-.2-.56-.53-.91-.98-.91H7.83c-.44 0-.76.35-.97.9L.02 30.31Zm42.37-5.97c0 1.64-2.05 2.62-4.88 2.62-1.85 0-2.5-.45-2.5-1.41 0-1 .8-1.49 2.65-1.49 1.67 0 3.09.03 4.73.23v.05Zm.03-2.04a21.37 21.37 0 0 0-4.37-.36c-5.32 0-7.82 1.25-7.82 4.18 0 3.04 1.71 4.2 5.68 4.2 3.35 0 5.63-.84 6.46-2.92h.14c-.03.5-.05 1-.05 1.4 0 1.07.18 1.16 1.06 1.16h4.15a16.9 16.9 0 0 1-.36-4c0-1.67.06-2.93.06-4.62 0-3.45-2.07-5.64-8.56-5.64-2.8 0-5.9.48-8.26 1.19.22.93.54 2.83.7 4.06 2.04-.96 4.95-1.37 7.2-1.37 3.11 0 3.97.71 3.97 2.15v.57Zm11.37 3c-.56.07-1.33.07-2.12.07-.83 0-1.6-.03-2.12-.1l-.02.58c0 2.85 1.87 4.52 8.45 4.52 6.2 0 8.2-1.64 8.2-4.55 0-2.74-1.33-4.09-7.2-4.39-4.58-.2-4.99-.7-4.99-1.28 0-.66.59-1 3.65-1 3.18 0 4.03.43 4.03 1.35v.2a46.13 46.13 0 0 1 4.24.03l.02-.55c0-3.36-2.8-4.46-8.2-4.46-6.08 0-8.13 1.49-8.13 4.39 0 2.6 1.64 4.23 7.48 4.48 4.3.14 4.77.62 4.77 1.28 0 .7-.7 1.03-3.71 1.03-3.47 0-4.35-.48-4.35-1.47v-.13Zm19.82-12.05a17.5 17.5 0 0 1-6.24 3.48c.03.84.03 2.4.03 3.24l1.5.02c-.02 1.63-.04 3.6-.04 4.9 0 3.04 1.6 5.32 6.58 5.32 2.1 0 3.5-.23 5.23-.6a43.77 43.77 0 0 1-.46-4.13c-1.03.34-2.34.53-3.78.53-2 0-2.82-.55-2.82-2.13 0-1.37 0-2.65.03-3.84 2.57.02 5.13.07 6.64.11-.02-1.18.03-2.9.1-4.04-2.2.04-4.65.07-6.68.07l.07-2.93h-.16Zm13.46 6.04a767.33 767.33 0 0 1 .07-3.18H82.6c.07 1.96.07 3.98.07 6.92 0 2.95-.03 4.99-.07 6.93h5.18c-.09-1.37-.11-3.68-.11-5.65 0-3.1 1.26-4 4.12-4 1.33 0 2.28.16 3.1.46.03-1.16.26-3.43.4-4.43-.86-.25-1.81-.41-2.96-.41-2.46-.03-4.26.98-5.1 3.38l-.17-.02Zm22.55 3.65c0 2.5-1.8 3.66-4.64 3.66-2.81 0-4.61-1.1-4.61-3.66s1.82-3.52 4.61-3.52c2.82 0 4.64 1.03 4.64 3.52Zm4.71-.11c0-4.96-3.87-7.18-9.35-7.18-5.5 0-9.23 2.22-9.23 7.18 0 4.94 3.49 7.59 9.21 7.59 5.77 0 9.37-2.65 9.37-7.6Z"/><defs><linearGradient id="a" x1="6.33" x2="19.43" y1="40.8" y2="34.6" gradientUnits="userSpaceOnUse"><stop stop-color="#D83333"/><stop offset="1" stop-color="#F041FF"/></linearGradient></defs></svg>
-1
src/assets/background.svg
···
-
<svg xmlns="http://www.w3.org/2000/svg" width="1440" height="1024" fill="none"><path fill="url(#a)" fill-rule="evenodd" d="M-217.58 475.75c91.82-72.02 225.52-29.38 341.2-44.74C240 415.56 372.33 315.14 466.77 384.9c102.9 76.02 44.74 246.76 90.31 366.31 29.83 78.24 90.48 136.14 129.48 210.23 57.92 109.99 169.67 208.23 155.9 331.77-13.52 121.26-103.42 264.33-224.23 281.37-141.96 20.03-232.72-220.96-374.06-196.99-151.7 25.73-172.68 330.24-325.85 315.72-128.6-12.2-110.9-230.73-128.15-358.76-12.16-90.14 65.87-176.25 44.1-264.57-26.42-107.2-167.12-163.46-176.72-273.45-10.15-116.29 33.01-248.75 124.87-320.79Z" clip-rule="evenodd" style="opacity:.154"/><path fill="url(#b)" fill-rule="evenodd" d="M1103.43 115.43c146.42-19.45 275.33-155.84 413.5-103.59 188.09 71.13 409 212.64 407.06 413.88-1.94 201.25-259.28 278.6-414.96 405.96-130 106.35-240.24 294.39-405.6 265.3-163.7-28.8-161.93-274.12-284.34-386.66-134.95-124.06-436-101.46-445.82-284.6-9.68-180.38 247.41-246.3 413.54-316.9 101.01-42.93 207.83 21.06 316.62 6.61Z" clip-rule="evenodd" style="opacity:.154"/><defs><linearGradient id="b" x1="373" x2="1995.44" y1="1100" y2="118.03" gradientUnits="userSpaceOnUse"><stop stop-color="#D83333"/><stop offset="1" stop-color="#F041FF"/></linearGradient><linearGradient id="a" x1="107.37" x2="1130.66" y1="1993.35" y2="1026.31" gradientUnits="userSpaceOnUse"><stop stop-color="#3245FF"/><stop offset="1" stop-color="#BC52EE"/></linearGradient></defs></svg>
+1
src/assets/butterfly.svg
···
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-butterfly-icon lucide-butterfly"><path d="M15.8 2C12 3.8 12 9 12 9s0-5.2-3.8-7"/><path d="M12 9v11"/><path d="M20 5c-3.5 0-6.5 3.9-8 6.3C10.5 8.9 7.5 5 4 5a2 2 0 0 0-2 2c0 2.3.6 4.4 1.5 5.6C4 13.5 4.9 14 6 14h2c-.9.4-2.1.9-2.6 1.5-1.6 1.6-.9 3.4.7 4.9 1.6 1.6 3.4 2.3 4.9.7.3-.3 1-1.1 1-1.1s.6.8 1 1.1c1.6 1.6 3.4.9 4.9-.7 1.6-1.6 2.3-3.4.7-4.9-.5-.5-1.7-1.1-2.6-1.5h2c1.1 0 2-.5 2.5-1.4.9-1.2 1.5-3.3 1.5-5.6a2 2 0 0 0-2-2"/></svg>
+34
src/components/Badgebar.astro
···
+
---
+
import LucideIcon from "./LucideIcon.astro";
+
+
interface Badge {
+
icon: string | any,
+
href: string
+
color: string
+
svg?: boolean
+
}
+
+
interface Props {
+
badges: Badge[]
+
size: string
+
}
+
+
const { badges, size } = Astro.props
+
+
---
+
<span class="flex gap-2 bg-ctp-crust p-2 pl-3 pr-3 rounded-full h-min">
+
{badges.map(badge =>
+
<a href=`${badge.href}` target="_blank" rel="noopener noreferrer">
+
{ badge.svg && badge.icon && (
+
<badge.icon width={size} height={size} style={`stroke:${badge.color}`}
+
class="hover:rotate-15 hover:scale-110 ease-in hover:ease-out transition-transform active:scale-80"
+
/>
+
)}
+
{ !badge.svg && (
+
<LucideIcon name=`${badge.icon}` width=`${size}` height=`${size}` style={`stroke:${badge.color}`}
+
class="hover:rotate-15 hover:scale-110 ease-in hover:ease-out transition-transform active:scale-80"
+
/>
+
)}
+
</a>
+
)}
+
</span>
+21
src/components/Footer.astro
···
+
---
+
import { Heart, Rocket, Copyright, Code } from "@lucide/astro"
+
---
+
<div class="flex justify-between bg-ctp-base p-6 pl-12 pr-12">
+
<span class="inline-flex gap-2 items-center">
+
Copyright
+
<Copyright size="20" class="stroke-ctp-text"/>
+
2026 Banana
+
</span>
+
<span class="inline-flex gap-2 items-center">
+
<a href="https://tangled.org/@banana.tngl.sh/mywebsite-2026"
+
class="text-xs text-ctp-overlay0 flex gap-1 hover:underline"><Code size="16" />src</a>
+
+
</span>
+
<span class="inline-flex gap-2 items-center">
+
Made with
+
<Heart size="20" class="stroke-ctp-red"/>
+
using Astro
+
<Rocket size="20" class="stroke-ctp-lavender"/>
+
</span>
+
</div>
+28
src/components/GithubCalendar.jsx
···
+
import React from 'react';
+
+
export default function GitHubWrapper({ username, ...props }) {
+
const [GitHubCalendar, setGitHubCalendar] = React.useState(null);
+
+
const theme = {
+
dark: [
+
'var(--catppuccin-color-crust)',
+
'var(--catppuccin-color-green-900)',
+
'var(--catppuccin-color-green-500)',
+
'var(--catppuccin-color-green-200)',
+
'var(--catppuccin-color-green-50)',
+
],
+
};
+
React.useEffect(() => {
+
import('react-github-calendar').then((module) => {
+
setGitHubCalendar(() => module.default);
+
});
+
}, []);
+
+
if (!GitHubCalendar) {
+
return <div>Loading GitHub calendar...</div>;
+
}
+
+
return <GitHubCalendar username={username} theme={theme}
+
blockMargin={3} blockRadius={1} blockSize={10}
+
{...props} />;
+
}
+12
src/components/Label.astro
···
+
---
+
interface Props {
+
name: string;
+
}
+
+
const { name } = Astro.props;
+
---
+
+
<span
+
class=`absolute top-[-0.5rem] left-3 text-xs text-ctp-overlay1 bg-ctp-mantle pl-2 pr-2`
+
>{name}</span
+
>
+12
src/components/LucideIcon.astro
···
+
---
+
import { icons, type IconProps } from '@lucide/astro';
+
+
interface Props extends IconProps {
+
name: keyof typeof icons;
+
}
+
+
const { name, ...restProps } = Astro.props;
+
const Icon = icons[name];
+
---
+
+
<Icon {...restProps} />
-20
src/components/Navbar.astro
···
-
---
-
import Btn from "./NavbarLink.astro"
-
---
-
<div class="bg-ctp-base w-full pl-8 pr-8 pt-4 pb-4 flex justify-between rounded-bl-2xl rounded-br-2xl">
-
<div class="flex gap-4 items-center">
-
<a href="/doodlecat.png"><img src="doodlecat.png" width="48px" height="48px" class="rounded-full" /></a>
-
<span>~/banana/home</span>
-
</div>
-
<div class="flex gap-6 items-center">
-
<Btn page="home"/>
-
<Btn page="projects"/>
-
<Btn page="experience"/>
-
</div>
-
</div>
-
<style>
-
@reference "../styles/global.css"
-
a {
-
@apply ;
-
}
-
</style>
-17
src/components/NavbarLink.astro
···
-
---
-
interface Props {
-
page: String;
-
}
-
const {page} = Astro.props
-
---
-
<a
-
href=`/${page}`
-
class="font-bold
-
text-ctp-yellow hover:text-ctp-blue
-
hover:underline
-
ease-in hover:ease-out transition-all
-
">{page}</a>
-
-
-
-
+79
src/components/PortfolioItem.astro
···
+
---
+
interface Badge {
+
icon: string,
+
href: string
+
color: string
+
}
+
+
interface Props {
+
type: string
+
icon?: string,
+
title: string,
+
subtitle: string,
+
tag?: string,
+
tagcolor?: string,
+
href: string
+
badges?: Badge[]
+
}
+
+
const { type, icon = "Box", title, subtitle, tag, tagcolor, href, badges } = Astro.props
+
+
var color = "--catppuccin-color-yellow"
+
if (type=="project") {
+
color = "--catppuccin-color-red"
+
} else if (type=="repo") {
+
color = "--catppuccin-color-peach"
+
} else if (type=="team") {
+
color = "--catppuccin-color-mauve"
+
} else if (type=="misc") {
+
color = "--catppuccin-color-maroon"
+
} else if (type=="freelance") {
+
color = "--catppuccin-color-sky"
+
}
+
const colorCss = "var(" + color + ")"
+
+
var iconName = icon
+
if (iconName == "Box") {
+
if (type=="project") {
+
iconName = "Archive"
+
} else if (type=="repo") {
+
iconName = "BookMarked"
+
} else if (type=="team") {
+
iconName = "Users"
+
} else if (type=="misc") {
+
iconName = "Box"
+
} else if (type=="freelance") {
+
iconName = "ReceiptText"
+
}
+
}
+
+
import LucideIcon from "./LucideIcon.astro"
+
import Badgebar from "./Badgebar.astro"
+
import Tag from "./Tag.astro"
+
---
+
<div class="p-4 border border-ctp-surface0 flex flex-col -mt-px w-full">
+
<div class="flex flex-wrap sm:flex-nowrap justify-between gap-2 sm:gap-4">
+
<a href=`${href}` class="flex flex-col gap-1 group">
+
<span class="text-xl flex gap-2 items-center">
+
<LucideIcon name=`${iconName}` width="20" height="20" style={`stroke:${colorCss}`} />
+
<span class="group-hover:underline font-bold">{title} </span>
+
<span class="hidden md:flex items-center">
+
{tag && tagcolor && (
+
<Tag text={tag} color={tagcolor}/>
+
)}
+
</span>
+
</span>
+
<span class="text-sm">
+
<span class="flex gap-1">{subtitle}</span>
+
</span>
+
</a>
+
<span>
+
{ badges && (
+
<Badgebar badges={badges} size="20"/>
+
)}
+
</span>
+
</div>
+
<div>
+
<slot/>
+
</div>
+
</div>
+8 -7
src/components/Tag.astro
···
---
interface Props {
-
name: string;
+
text: string
+
color: string
}
-
const { name } = Astro.props;
+
const { text, color } = Astro.props
+
const colorCss = "var(" + color + "-700)"
---
-
-
<span
-
class=`absolute top-[-0.5rem] left-2 text-xs text-ctp-overlay0 bg-ctp-mantle pl-2 pr-2`
-
>{name}</span
-
>
+
<span class="p-1 pl-2 pr-2 text-xs rounded-full font-bold bg-ctp-base border border-ctp-surface0"
+
style={`color:${colorCss};`}>
+
{text}
+
</span>
+27
src/components/navbar/Navbar.astro
···
+
---
+
import Btn from "./NavbarLink.astro"
+
+
let href = Astro.url.toString()
+
href = href.replace(Astro.url.host.toString(), "")
+
href = href.replace("https://", "")
+
href = href.replace("http://", "")
+
---
+
<div class="fixed z-40 bg-ctp-base
+
left-[2%] right-[2%] md:left-[4%] md:right-[4%] xl:left-[8%] xl:right-[8%]
+
pl-8 pr-8 pt-4 pb-4 flex justify-between rounded-bl-2xl rounded-br-2xl squircle">
+
<div class="flex gap-4 items-center">
+
<span class="flex flex-col">
+
<span>~/banana{href}</span>
+
</span>
+
</div>
+
<div class="flex gap-6 items-center">
+
<Btn page="home"/>
+
<Btn page="projects"/>
+
</div>
+
</div>
+
<style>
+
@reference "../../styles/global.css"
+
a {
+
@apply ;
+
}
+
</style>
+21
src/components/navbar/NavbarLink.astro
···
+
---
+
interface Props {
+
page: String;
+
}
+
const {page} = Astro.props
+
var href = page
+
if (href == "home") {
+
href = ""
+
}
+
---
+
<a
+
href=`/${href}`
+
class="font-bold
+
text-ctp-yellow hover:text-ctp-blue
+
hover:underline
+
ease-in hover:ease-out transition-all
+
">{page}</a>
+
+
+
+
+34
src/components/projects/BiomeBattle.astro
···
+
---
+
import Item from "../PortfolioItem.astro"
+
---
+
<Item
+
type="freelance"
+
title="BiomeBattle"
+
subtitle="A modern Minecraft creator event. As a developer, I helped with minor improvements to the cosmetics system."
+
icon="Earth"
+
href="https://biomebattle.xyz/"
+
tag="Java"
+
tagcolor="--catppuccin-color-teal"
+
badges={[
+
{
+
icon: "Bird",
+
href: "https://x.com/biomebattle",
+
color: "var(--catppuccin-color-sapphire)"
+
},
+
{
+
icon: "Github",
+
href: "https://github.com/biomebattle",
+
color: "var(--catppuccin-color-green)"
+
},
+
{
+
icon: "MessageCircle",
+
href: "https://biomebattle.xyz/discord",
+
color: "var(--catppuccin-color-blue)"
+
},
+
{
+
icon: "Youtube",
+
href: "https://youtube.com/@BiomeBattle",
+
color: "var(--catppuccin-color-red)"
+
},
+
]}
+
/>
+24
src/components/projects/Dotfiles.astro
···
+
---
+
import Item from "../PortfolioItem.astro"
+
export const priority = 1;
+
---
+
<Item
+
type="repo"
+
title="dotfiles"
+
subtitle="My personal configuration dotfiles for endeavouros linux."
+
href="https://tangled.org/@banana.tngl.sh/dotfiles"
+
badges={[
+
{
+
icon: "Github",
+
href: "https://github.com/imabanana80/dotfiles",
+
color: "var(--catppuccin-color-green)"
+
},
+
+
{
+
icon: "Book",
+
href: "https://wiki.archlinux.org/title/Dotfiles",
+
color: "var(--catppuccin-color-sapphire)"
+
},
+
]}
+
/>
+
+28
src/components/projects/IsleStats.astro
···
+
---
+
import Item from "../PortfolioItem.astro"
+
---
+
<Item
+
type="project"
+
title="IsleStats"
+
subtitle="An MCC Island Discord statistics bot that renders beautiful stat cards to show off your stats."
+
href="https://islestats.net"
+
tag="Python"
+
tagcolor="--catppuccin-color-blue"
+
badges={[
+
{
+
icon: "Github",
+
href: "https://github.com/islestats",
+
color: "var(--catppuccin-color-green)"
+
},
+
{
+
icon: "MessageCircle",
+
href: "https://discord.gg//islestats",
+
color: "var(--catppuccin-color-blue)"
+
},
+
{
+
icon: "Mail",
+
href: "mailto:contact@islestats.net",
+
color: "var(--catppuccin-color-maroon)"
+
}
+
]}
+
/>
+24
src/components/projects/MyWebsite2026.astro
···
+
---
+
import Item from "../PortfolioItem.astro"
+
---
+
<Item
+
type="repo"
+
title="my-website-2026"
+
subtitle="My portfolio website for the year 2026 built with Astro. This is the current website you're on."
+
href="https://beta.imabanana80.com/"
+
tag="Astro"
+
tagcolor="--catppuccin-color-pink"
+
badges={[
+
{
+
icon: "Spool",
+
href: "https://tangled.org/@banana.tngl.sh/mywebsite-2026",
+
color: "var(--catppuccin-color-lavender)"
+
},
+
{
+
icon: "Github",
+
href: "https://github.com/imabanana80/mywebsite-2026",
+
color: "var(--catppuccin-color-green)"
+
},
+
]}
+
/>
+
+18
src/components/projects/PassgenAstro.astro
···
+
---
+
import Item from "../PortfolioItem.astro"
+
---
+
<Item
+
type="repo"
+
title="passgen-astro"
+
subtitle="Static client-based password phrase generator built with astro."
+
href="https://pass.imabanana80.com"
+
tag="Astro"
+
tagcolor="--catppuccin-color-pink"
+
badges={[
+
{
+
icon: "Github",
+
href: "https://github.com/imabanana80/passgen-astro",
+
color: "var(--catppuccin-color-green)"
+
},
+
]}
+
/>
+29
src/components/projects/PotassiumSh.astro
···
+
---
+
import Item from "../PortfolioItem.astro"
+
export const priority = 2;
+
---
+
<Item
+
type="team"
+
title="potassium.sh"
+
subtitle="An indie software development studio for the creative and insane, founded by me, with some friends!"
+
href="https://potassium.sh"
+
tag="Founder"
+
tagcolor="--catppuccin-color-rosewater"
+
badges={[
+
{
+
icon: "Mail",
+
href: "mailto:team@potassium.sh",
+
color: "var(--catppuccin-color-maroon)"
+
},
+
{
+
icon: "Spool",
+
href: "https://tangled.org/@potassium.sh",
+
color: "var(--catppuccin-color-lavender)"
+
},
+
{
+
icon: "Bird",
+
href: "https://bsky.app/profile/potassium.sh",
+
color: "var(--catppuccin-color-sapphire)"
+
},
+
]}
+
/>
+18
src/components/projects/SMPSales.astro
···
+
---
+
import Item from "../PortfolioItem.astro"
+
---
+
<Item
+
type="team"
+
title="SMP Sales"
+
subtitle="A Minecraft SMP freelancing hub, from developers to artists, all you'll need to start an SMP of your own."
+
href="https://discord.gg/DUa3asXpvs"
+
tag="Developer"
+
tagcolor="--catppuccin-color-rosewater"
+
badges={[
+
{
+
icon: "Github",
+
href: "https://github.com/smpsales",
+
color: "var(--catppuccin-color-green)"
+
},
+
]}
+
/>
+11
src/components/projects/StatusPage.astro
···
+
---
+
import Item from "../PortfolioItem.astro"
+
---
+
<Item
+
type="project"
+
title="Status Page"
+
subtitle="A custom status page design that could automatically fetch data from a custom api to display live information."
+
href="https://status.imabanana80.com"
+
tag="Astro"
+
tagcolor="--catppuccin-color-pink"
+
/>
+9
src/components/section/Contributions.astro
···
+
---
+
import Label from "../Label.astro"
+
import GitHubCalendar from "../GithubCalendar"
+
---
+
+
<div class="flex flex-col p-8 border-ctp-surface0 border w-full h-min relative">
+
<Label name="Contributions"/>
+
<GitHubCalendar client:load username="imabanana80"/>
+
</div>
+62
src/components/section/MusicPlayer.astro
···
+
---
+
import Label from "../Label.astro"
+
import { Disc } from "@lucide/astro"
+
---
+
<div class="border border-ctp-surface0 p-8 pt-6 pb-6 relative">
+
<Label name="Music Player" />
+
<div id="music">
+
<audio
+
id="audio"
+
controls
+
src="/celeste_exhale.mp3"
+
class="hidden"
+
></audio>
+
<div class="mb-1">
+
<span class="text-base flex gap-2 items-center w-fit">
+
<Disc size="20" class="stroke-ctp-pink"/>
+
Celeste - Exhale
+
<span class="text-sm text-ctp-overlay0">by Lena Raine</span>
+
</span>
+
</div>
+
<div id="controls" class="flex gap-1">
+
<button id="control-button" class=""><img id="control-img" src="/play.svg"></button>
+
<div id="progress-bar" class="self-center border border-ctp-surface1 w-full h-1">
+
<div id="progress" class="bg-ctp-subtext0 h-[0.25rem] w-0"></div>
+
</div>
+
</div>
+
</div>
+
</div>
+
<script>
+
const controlButton = document.getElementById("control-button") as HTMLElement
+
const controlImg = document.getElementById("control-img") as HTMLImageElement
+
const audio = document.getElementById("audio") as HTMLAudioElement
+
const progressBar = document.getElementById("progress-bar") as HTMLElement
+
const progress = document.getElementById("progress") as HTMLElement
+
+
controlButton.addEventListener("click", () => {
+
if (audio.paused) {
+
audio.play();
+
controlImg.src = "/pause.svg"
+
} else {
+
audio.pause();
+
controlImg.src = "/play.svg"
+
}
+
});
+
+
audio.addEventListener("timeupdate", () => {
+
progress.style.width = `${(audio.currentTime / audio.duration) * 100}%`;
+
});
+
+
audio.addEventListener("ended", () => {
+
audio.currentTime = 0;
+
progress.style.width = "0%";
+
audio.play();
+
});
+
+
progressBar.addEventListener("click", (e) => {
+
const clickPosition =
+
(e.offsetX / progressBar.clientWidth) * audio.duration;
+
audio.currentTime = clickPosition;
+
});
+
</script>
+
+15
src/components/section/Pinned.astro
···
+
---
+
import Label from "../Label.astro"
+
import Dotfiles from "../projects/Dotfiles.astro"
+
import IsleStats from "../projects/IsleStats.astro"
+
import Potassium from "../projects/PotassiumSh.astro"
+
---
+
+
<div class="flex flex-col p-8 border-ctp-surface0 border w-full h-min relative">
+
<Label name="Pinned"/>
+
<div class="flex flex-wrap">
+
<IsleStats/>
+
<Potassium />
+
<Dotfiles />
+
</div>
+
</div>
+102
src/components/section/Profile.astro
···
+
---
+
import Label from '../Label.astro';
+
import Quote from './Quote.astro'
+
import BadgeBar from "../Badgebar.astro"
+
import Butterfly from "../../assets/butterfly.svg"
+
+
let home = "hidden lg:flex"
+
if (Astro.url.pathname == "/") {
+
home = "flex"
+
}
+
---
+
<div class=`${home} flex-col md:col-span-2 border border-ctp-surface0 gap-[-1px] w-full h-min`>
+
<span class="p-4 pb-0 border-b border-ctp-surface0 relative">
+
<img src="/banner.png" class="w-full"/>
+
</span>
+
<div class="p-8 pt-12 flex-col flex flex-wrap relative">
+
<img src="/doodlecat.png" width="96px" height="96px"
+
class="rounded-full absolute -top-12 left-8 border-6 border-ctp-mantle" />
+
<span class="text-base flex justify-between w-full flex-wrap gap-2">
+
<span class="flex flex-col">
+
<span class="text-2xl font-bold">Banana</span>
+
<a href="mailto:banana@potassium.sh" class="hover:underline ease-in hover:ease-out transition-all">
+
banana@potassium.sh</a>
+
</span>
+
<BadgeBar
+
badges={[
+
{
+
icon: "Github",
+
color: "var(--catppuccin-color-green)",
+
href: "https://github.com/imabanana80"
+
},
+
{
+
icon: "Spool",
+
color: "var(--catppuccin-color-lavender)",
+
href: "https://tangled.org/@banana.tngl.sh"
+
},
+
{
+
icon: Butterfly,
+
color: "var(--catppuccin-color-sapphire)",
+
href: "https://bsky.app/profile/imabanana80.com",
+
svg: true
+
}
+
]}
+
size='20'
+
/>
+
</span>
+
<span class="relative p-3 mt-4 border border-ctp-surface0 text-sm">
+
<Label name="Currently"/>
+
Switching to endeavoros | Open for Hire
+
</span>
+
<span class="relative p-3 mt-4 border border-ctp-surface0 text-sm">
+
<Label name="About"/>
+
Hi, I'm Banana, a computer science student and software developer that specialises in
+
Web Development as well as developing and hosting Minecraft Events.
+
</span>
+
<span class="relative p-3 mt-4 border border-ctp-surface0 text-ctp-subtext0 text-sm">
+
<Label name="Time"/>
+
<span id="clock" class="text-ctp-text"></span> (SGT/UTC+8)
+
</span>
+
<span class="relative p-3 mt-4 border border-ctp-surface0 text-sm">
+
<Label name="Languages"/>
+
<span>Java, Python, Golang, HTML/CSS/TS</span>
+
</span>
+
<span class="relative p-3 -mt-px border border-ctp-surface0 text-sm">
+
<Label name="Frameworks"/>
+
<span>PaperMC, Astro, Tailwindcss</span>
+
</span>
+
<span class="relative p-3 -mt-px border border-ctp-surface0 text-sm">
+
<Label name="Tools"/>
+
<span>Neovim, IntellIJ, Figma, VSC*de</span>
+
</span>
+
<div class="mt-4 flex">
+
<Quote />
+
</div>
+
</div >
+
</div>
+
+
+
<script>
+
const clockElement: HTMLElement | null = document.getElementById("clock");
+
+
if (!clockElement) {
+
console.error(`Error: Clock element with ID "clock" not found.`);
+
}
+
+
const displayTime = (): void => {
+
const now: Date = new Date();
+
+
const options: Intl.DateTimeFormatOptions = {
+
hour: '2-digit',
+
minute: '2-digit',
+
second: '2-digit',
+
hour12: false,
+
timeZone: "Asia/Singapore"
+
};
+
+
const timeString: string = now.toLocaleTimeString('en-US', options);
+
clockElement.textContent = timeString;
+
};
+
displayTime();
+
setInterval(displayTime, 1000);
+
</script>
+19
src/components/section/Projects.astro
···
+
---
+
import Label from "../Label.astro"
+
let projects = Object.values(import.meta.glob('../projects/*.astro', { eager: true }));
+
+
projects = projects.sort((a, b) => {
+
const projectA = a.priority ?? Infinity;
+
const projectB = b.priority ?? Infinity;
+
+
return projectA - projectB
+
})
+
---
+
<div class="flex flex-col p-8 border-ctp-surface0 border w-full h-min relative">
+
<Label name="Projects"/>
+
<div class="flex flex-wrap gap-4">
+
{projects.map(Project => (
+
<Project.default />
+
))}
+
</div>
+
</div>
+35
src/components/section/Quote.astro
···
+
---
+
import Label from "../Label.astro"
+
---
+
<script>
+
interface Quote {
+
quote: string,
+
quotee: string,
+
}
+
const quoteElement = document.getElementById("quote") as HTMLElement
+
const quoteeElement = document.getElementById("quotee") as HTMLElement
+
+
const quotes: Quote[] = [
+
{ quote: "America is a nation that can be defined in a single word: asufutimaehaehfutbw", quotee: "Joseph Robinette Biden Jr."},
+
{ quote: "What if they- what if anything- what if a bomb drops on your head right now?", quotee: "Donald John Trump"},
+
{ quote: "This is a tough hurricane. One of the wettest we've ever seen from the standpoint of water.", quotee: "Donald John Trump"},
+
{ quote: "Heh heh heh, oh it's focused. I say it's err- I think it's- I- I- I haven't-- look.", quotee: "Joseph Robinette Biden Jr."},
+
{ quote: "the color orange is named after the fruit", quotee: "Elon Reeve Musk" },
+
{ quote: "I'm excited about electric school busses, I love electric school busses, I just love them..", quotee: "Kamala Devi Harris"},
+
{ quote: "How dare we speak marry christmas! How dare we!", quotee: "Kamala Devi Harris"},
+
{ quote: "One thing that really encourages me is AI. I love AI. I love ChatGPT. I love it. ChatGPT is frankly fantastic.", quotee: "Alexander Boris de Pfeffel Johnson" },
+
{ quote: "I am a fighter and not a quitter!", quotee: "Elizabeth Mary Truss" },
+
{ quote: "I call again for an immediate ceasefire in Gaza, the return of the sausages- the hostages..", quotee: "Keir Rodney Starmer" },
+
]
+
const quote: Quote = quotes[Math.floor(Math.random()*quotes.length)]
+
+
quoteElement.textContent = '"' + quote.quote + '"'
+
quoteeElement.textContent = "- " + quote.quotee
+
</script>
+
<span class="relative p-3 -mt-px border border-ctp-surface0 text-sm w-full">
+
<Label name="Quote"/>
+
<div class="flex flex-col text-sm gap-1">
+
<span id="quote" class="italic"></span>
+
<span id="quotee" class="w-full text-right"></span>
+
</div>
+
</span>
+9 -5
src/layouts/Layout.astro
···
---
import "../styles/global.css"
-
import Navbar from "../components/Navbar.astro"
+
import Navbar from "../components/navbar/Navbar.astro"
+
import Footer from "../components/Footer.astro"
---
<!doctype html>
<html lang="en">
···
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
<meta name="generator" content={Astro.generator} />
-
<title>banana@potassium.sh</title>
+
<title>banana's page</title>
</head>
-
<body class="bg-ctp-crust pl-64 pr-64 text-ctp-text">
-
<main class="w-full min-h-full max-h-max bg-ctp-mantle">
+
<body class="bg-ctp-crust pl-[2%] pr-[2%]
+
md:pl-[4%] md:pr-[4%] xl:pl-[8%] xl:pr-[8%]
+
text-ctp-text">
+
<main class="w-full min-h-full max-h-max bg-ctp-mantle relative">
<Navbar/>
-
<slot />
+
<slot />
</main>
+
<Footer />
</body>
</html>
<script>
+14
src/layouts/Page.astro
···
+
---
+
import Layout from './Layout.astro';
+
import Profile from "../components/section/Profile.astro";
+
---
+
<Layout>
+
<section class="h-[50%]
+
flex flex-col lg:grid-cols-5 lg:grid
+
p-10 pt-15 md:p-12 md:pt-18 xl:p-24 xl:pt-36 gap-4 md:gap-8 xl:gap-16">
+
<Profile/>
+
<div class="md:col-span-3 gap-4 md:gap-8 xl:gap-12 flex flex-col">
+
<slot/>
+
</div>
+
</section>
+
</Layout>
+25
src/pages/404.astro
···
+
---
+
import Layout from "../layouts/Layout.astro"
+
+
const urlPathname = Astro.url.pathname
+
const urlOrigin = Astro.url.origin
+
const astroGenerator = Astro.generator
+
const currentISODate = new Date().toISOString();
+
---
+
+
<Layout>
+
<section class="h-svh items-center flex pl-32 pr-32 ">
+
<div class="flex justify-between gap-8 w-full items-end">
+
<span class="text-9xl w-min">404 Not Found</span>
+
<div class="text-ctp-overlay0 flex flex-col items-end text-base p-4">
+
<span>HTTP/1.1 404 Not Found</span>
+
<span>Server: {astroGenerator}</span>
+
<span>Connection: keep-alive</span>
+
<span>Date: {currentISODate}</span>
+
<span>Content-Type: text/html; charset=utf-8</span>
+
<span>X-Request-Path: {urlPathname}</span>
+
<span>X-Request-Origin: {urlOrigin}</span>
+
</div>
+
</div>
+
</section>
+
</Layout>
+10 -83
src/pages/index.astro
···
---
-
import Layout from '../layouts/Layout.astro';
-
import Tag from '../components/Tag.astro';
-
import { Github, Twitch, Youtube, Icon } from '@lucide/astro'
-
import { butterfly } from '@lucide/lab'
-
---
-
<script>
-
const clockElement: HTMLElement | null = document.getElementById("clock");
-
-
if (!clockElement) {
-
console.error(`Error: Clock element with ID "clock" not found.`);
-
}
-
-
const displayTime = (): void => {
-
const now: Date = new Date();
+
import Page from '../layouts/Page.astro';
-
const options: Intl.DateTimeFormatOptions = {
-
hour: '2-digit',
-
minute: '2-digit',
-
second: '2-digit',
-
hour12: false,
-
timeZone: "Asia/Singapore"
-
};
-
-
const timeString: string = now.toLocaleTimeString('en-US', options);
-
clockElement.textContent = timeString;
-
};
-
displayTime();
-
setInterval(displayTime, 1000);
-
</script>
-
<Layout>
-
<section class="h-[50%] grid-cols-5 grid p-32 gap-12">
-
<div class="flex flex-col col-span-3 gap-3 p-8 border-ctp-surface0 border h-min">
-
<span class="text-5xl font-semibold">
-
Hi, I'm Banana.
-
</span>
-
<span class='text-lg'>
-
I'm a computer science student and software developer that specialises in
-
Web Development as well as developing and hosting Minecraft Events.
-
</span>
-
</div>
-
<div class="flex flex-col col-span-2 border border-ctp-surface0 gap-[-1px] w-full h-min">
-
<span class="p-4 pb-0 border-b border-ctp-surface0 relative">
-
<img src="/banner.png" class="w-full"/>
-
</span>
-
<div class="p-8 pt-12 flex-col flex relative">
-
<img src="doodlecat.png" width="96px" height="96px"
-
class="rounded-full absolute -top-12 left-8 border-6 border-ctp-mantle" />
-
<span class="text-base flex justify-between">
-
<span class="flex flex-col">
-
<span class="text-2xl font-bold">Banana</span>
-
<a href="mailto:banana@potassium.sh" class="hover:underline ease-in hover:ease-out transition-all">banana@potassium.sh</a>
-
</span>
-
<span class="flex gap-2 bg-ctp-crust p-2 pl-3 pr-3 rounded-full h-min">
-
<a href="https://github.com/imabanana80">
-
<Github size="20"
-
class="stroke-ctp-green hover:rotate-15 ease-in hover:ease-out transition-transform"/></a>
-
<a href="https://bsky.app/profile/imabanana80.com">
-
<Icon iconNode={butterfly} size="20"
-
class="stroke-ctp-sapphire hover:rotate-15 ease-in hover:ease-out transition-transform"/></a>
-
<a href="https://twitch.tv/imabanana80">
-
<Twitch size="20"
-
class="stroke-ctp-mauve hover:rotate-15 ease-in hover:ease-out transition-transform"/></a>
-
<a href="https://youtube.com/@imabanana80">
-
<Youtube size="20"
-
class="stroke-ctp-red hover:rotate-15 ease-in hover:ease-out transition-transform"/></a>
-
</span>
-
</span>
-
<span class="relative p-3 mt-4 border border-ctp-surface0 text-sm">
-
<Tag name="About"/>
-
Hi, I'm Banana, a computer science student and software developer that specialises in
-
Web Development as well as developing and hosting Minecraft Events.
-
</span>
-
<span class="relative p-3 mt-4 border border-ctp-surface0 text-sm">
-
<Tag name="Currently"/>
-
Learning Svelte | Open for Hire
-
</span>
-
<span class="relative p-3 -mt-px border border-ctp-surface0 text-ctp-subtext0 text-sm">
-
<Tag name="Time"/>
-
<span id="clock" class="text-ctp-text"></span> (SGT/UTC+8)
-
</span>
-
</div >
-
</div>
-
</section>
-
</Layout>
+
import Contributions from "../components/section/Contributions.astro"
+
import Pinned from "../components/section/Pinned.astro"
+
import MusicPlayer from "../components/section/MusicPlayer.astro"
+
---
+
<Page>
+
<Contributions/>
+
<Pinned/>
+
<MusicPlayer/>
+
</Page>
+7
src/pages/projects.astro
···
+
---
+
import Page from '../layouts/Page.astro';
+
import ProjectsC from "../components/section/Projects.astro"
+
---
+
<Page>
+
<ProjectsC/>
+
</Page>
+4
src/styles/global.css
···
--ease-out: cubic-bezier(0,0.69,0.44,0.99);
--default-font-family: "JetBrains Mono", monospaced;
}
+
+
.squircle {
+
corner-shape: squircle
+
}
+12 -3
tsconfig.json
···
{
"extends": "astro/tsconfigs/strict",
-
"include": [".astro/types.d.ts", "**/*"],
-
"exclude": ["dist"]
-
}
+
"include": [
+
".astro/types.d.ts",
+
"**/*"
+
],
+
"exclude": [
+
"dist"
+
],
+
"compilerOptions": {
+
"jsx": "react-jsx",
+
"jsxImportSource": "react"
+
}
+
}