website: add downloads pages

This commit is contained in:
Kingkor Roy Tirtho 2025-08-04 12:45:28 +06:00
parent 49e2d1b759
commit 7a630507fb
14 changed files with 913 additions and 5 deletions

View File

@ -10,18 +10,25 @@
}, },
"dependencies": { "dependencies": {
"@astrojs/react": "^4.3.0", "@astrojs/react": "^4.3.0",
"@octokit/rest": "^22.0.0",
"@skeletonlabs/skeleton-react": "^1.2.4", "@skeletonlabs/skeleton-react": "^1.2.4",
"@tailwindcss/vite": "^4.1.11", "@tailwindcss/vite": "^4.1.11",
"@types/react": "^19.1.9", "@types/react": "^19.1.9",
"@types/react-dom": "^19.1.7", "@types/react-dom": "^19.1.7",
"astro": "^5.12.8", "astro": "^5.12.8",
"date-fns": "^4.1.0",
"markdown-it": "^14.1.0",
"react": "^19.1.1", "react": "^19.1.1",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"react-icons": "^5.5.0", "react-icons": "^5.5.0",
"sanitize-html": "^2.17.0",
"tailwindcss": "^4.1.11", "tailwindcss": "^4.1.11",
"usehooks-ts": "^3.1.1" "usehooks-ts": "^3.1.1"
}, },
"devDependencies": { "devDependencies": {
"@skeletonlabs/skeleton": "^3.1.7" "@skeletonlabs/skeleton": "^3.1.7",
"@tailwindcss/typography": "^0.5.16",
"@types/markdown-it": "^14.1.2",
"@types/sanitize-html": "^2.16.0"
} }
} }

View File

@ -11,6 +11,9 @@ importers:
'@astrojs/react': '@astrojs/react':
specifier: ^4.3.0 specifier: ^4.3.0
version: 4.3.0(@types/node@24.1.0)(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(jiti@2.5.1)(lightningcss@1.30.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) version: 4.3.0(@types/node@24.1.0)(@types/react-dom@19.1.7(@types/react@19.1.9))(@types/react@19.1.9)(jiti@2.5.1)(lightningcss@1.30.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@octokit/rest':
specifier: ^22.0.0
version: 22.0.0
'@skeletonlabs/skeleton-react': '@skeletonlabs/skeleton-react':
specifier: ^1.2.4 specifier: ^1.2.4
version: 1.2.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) version: 1.2.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
@ -26,6 +29,12 @@ importers:
astro: astro:
specifier: ^5.12.8 specifier: ^5.12.8
version: 5.12.8(@types/node@24.1.0)(jiti@2.5.1)(lightningcss@1.30.1)(rollup@4.46.2)(typescript@5.9.2) version: 5.12.8(@types/node@24.1.0)(jiti@2.5.1)(lightningcss@1.30.1)(rollup@4.46.2)(typescript@5.9.2)
date-fns:
specifier: ^4.1.0
version: 4.1.0
markdown-it:
specifier: ^14.1.0
version: 14.1.0
react: react:
specifier: ^19.1.1 specifier: ^19.1.1
version: 19.1.1 version: 19.1.1
@ -35,6 +44,9 @@ importers:
react-icons: react-icons:
specifier: ^5.5.0 specifier: ^5.5.0
version: 5.5.0(react@19.1.1) version: 5.5.0(react@19.1.1)
sanitize-html:
specifier: ^2.17.0
version: 2.17.0
tailwindcss: tailwindcss:
specifier: ^4.1.11 specifier: ^4.1.11
version: 4.1.11 version: 4.1.11
@ -45,6 +57,15 @@ importers:
'@skeletonlabs/skeleton': '@skeletonlabs/skeleton':
specifier: ^3.1.7 specifier: ^3.1.7
version: 3.1.7(tailwindcss@4.1.11) version: 3.1.7(tailwindcss@4.1.11)
'@tailwindcss/typography':
specifier: ^0.5.16
version: 0.5.16(tailwindcss@4.1.11)
'@types/markdown-it':
specifier: ^14.1.2
version: 14.1.2
'@types/sanitize-html':
specifier: ^2.16.0
version: 2.16.0
packages: packages:
@ -445,6 +466,58 @@ packages:
'@jridgewell/trace-mapping@0.3.29': '@jridgewell/trace-mapping@0.3.29':
resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==}
'@octokit/auth-token@6.0.0':
resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==}
engines: {node: '>= 20'}
'@octokit/core@7.0.3':
resolution: {integrity: sha512-oNXsh2ywth5aowwIa7RKtawnkdH6LgU1ztfP9AIUCQCvzysB+WeU8o2kyyosDPwBZutPpjZDKPQGIzzrfTWweQ==}
engines: {node: '>= 20'}
'@octokit/endpoint@11.0.0':
resolution: {integrity: sha512-hoYicJZaqISMAI3JfaDr1qMNi48OctWuOih1m80bkYow/ayPw6Jj52tqWJ6GEoFTk1gBqfanSoI1iY99Z5+ekQ==}
engines: {node: '>= 20'}
'@octokit/graphql@9.0.1':
resolution: {integrity: sha512-j1nQNU1ZxNFx2ZtKmL4sMrs4egy5h65OMDmSbVyuCzjOcwsHq6EaYjOTGXPQxgfiN8dJ4CriYHk6zF050WEULg==}
engines: {node: '>= 20'}
'@octokit/openapi-types@25.1.0':
resolution: {integrity: sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==}
'@octokit/plugin-paginate-rest@13.1.1':
resolution: {integrity: sha512-q9iQGlZlxAVNRN2jDNskJW/Cafy7/XE52wjZ5TTvyhyOD904Cvx//DNyoO3J/MXJ0ve3rPoNWKEg5iZrisQSuw==}
engines: {node: '>= 20'}
peerDependencies:
'@octokit/core': '>=6'
'@octokit/plugin-request-log@6.0.0':
resolution: {integrity: sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==}
engines: {node: '>= 20'}
peerDependencies:
'@octokit/core': '>=6'
'@octokit/plugin-rest-endpoint-methods@16.0.0':
resolution: {integrity: sha512-kJVUQk6/dx/gRNLWUnAWKFs1kVPn5O5CYZyssyEoNYaFedqZxsfYs7DwI3d67hGz4qOwaJ1dpm07hOAD1BXx6g==}
engines: {node: '>= 20'}
peerDependencies:
'@octokit/core': '>=6'
'@octokit/request-error@7.0.0':
resolution: {integrity: sha512-KRA7VTGdVyJlh0cP5Tf94hTiYVVqmt2f3I6mnimmaVz4UG3gQV/k4mDJlJv3X67iX6rmN7gSHCF8ssqeMnmhZg==}
engines: {node: '>= 20'}
'@octokit/request@10.0.3':
resolution: {integrity: sha512-V6jhKokg35vk098iBqp2FBKunk3kMTXlmq+PtbV9Gl3TfskWlebSofU9uunVKhUN7xl+0+i5vt0TGTG8/p/7HA==}
engines: {node: '>= 20'}
'@octokit/rest@22.0.0':
resolution: {integrity: sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA==}
engines: {node: '>= 20'}
'@octokit/types@14.1.0':
resolution: {integrity: sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==}
'@oslojs/encoding@1.1.0': '@oslojs/encoding@1.1.0':
resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==}
@ -680,6 +753,11 @@ packages:
resolution: {integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==} resolution: {integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
'@tailwindcss/typography@0.5.16':
resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==}
peerDependencies:
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
'@tailwindcss/vite@4.1.11': '@tailwindcss/vite@4.1.11':
resolution: {integrity: sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==} resolution: {integrity: sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==}
peerDependencies: peerDependencies:
@ -709,9 +787,18 @@ packages:
'@types/hast@3.0.4': '@types/hast@3.0.4':
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
'@types/linkify-it@5.0.0':
resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==}
'@types/markdown-it@14.1.2':
resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==}
'@types/mdast@4.0.4': '@types/mdast@4.0.4':
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
'@types/mdurl@2.0.0':
resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==}
'@types/ms@2.1.0': '@types/ms@2.1.0':
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
@ -729,6 +816,9 @@ packages:
'@types/react@19.1.9': '@types/react@19.1.9':
resolution: {integrity: sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA==} resolution: {integrity: sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA==}
'@types/sanitize-html@2.16.0':
resolution: {integrity: sha512-l6rX1MUXje5ztPT0cAFtUayXF06DqPhRyfVXareEN5gGCFaP/iwsxIyKODr9XDhfxPpN6vXUFNfo5kZMXCxBtw==}
'@types/unist@3.0.3': '@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
@ -874,6 +964,9 @@ packages:
base64-js@1.5.1: base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
before-after-hook@4.0.0:
resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==}
blob-to-buffer@1.2.9: blob-to-buffer@1.2.9:
resolution: {integrity: sha512-BF033y5fN6OCofD3vgHmNtwZWRcq9NLyyxyILx9hfMy1sXYy4ojFl765hJ2lP0YaN2fuxPaLO2Vzzoxy0FLFFA==} resolution: {integrity: sha512-BF033y5fN6OCofD3vgHmNtwZWRcq9NLyyxyILx9hfMy1sXYy4ojFl765hJ2lP0YaN2fuxPaLO2Vzzoxy0FLFFA==}
@ -984,6 +1077,9 @@ packages:
csstype@3.1.3: csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
date-fns@4.1.0:
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
debug@4.4.1: debug@4.4.1:
resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
engines: {node: '>=6.0'} engines: {node: '>=6.0'}
@ -996,6 +1092,10 @@ packages:
decode-named-character-reference@1.2.0: decode-named-character-reference@1.2.0:
resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==}
deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
defu@6.1.4: defu@6.1.4:
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
@ -1030,6 +1130,19 @@ packages:
dlv@1.1.3: dlv@1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
dom-serializer@2.0.0:
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
domelementtype@2.3.0:
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
domhandler@5.0.3:
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
engines: {node: '>= 4'}
domutils@3.2.2:
resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
dset@3.1.4: dset@3.1.4:
resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==}
engines: {node: '>=4'} engines: {node: '>=4'}
@ -1047,6 +1160,10 @@ packages:
resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==} resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==}
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}
entities@4.5.0:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
entities@6.0.1: entities@6.0.1:
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
engines: {node: '>=0.12'} engines: {node: '>=0.12'}
@ -1063,6 +1180,10 @@ packages:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'} engines: {node: '>=6'}
escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
escape-string-regexp@5.0.0: escape-string-regexp@5.0.0:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -1079,6 +1200,9 @@ packages:
extend@3.0.2: extend@3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
fast-content-type-parse@3.0.0:
resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==}
fast-deep-equal@3.1.3: fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
@ -1158,6 +1282,9 @@ packages:
html-void-elements@3.0.0: html-void-elements@3.0.0:
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
htmlparser2@8.0.2:
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
http-cache-semantics@4.2.0: http-cache-semantics@4.2.0:
resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==}
@ -1188,6 +1315,10 @@ packages:
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
engines: {node: '>=12'} engines: {node: '>=12'}
is-plain-object@5.0.0:
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
engines: {node: '>=0.10.0'}
is-wsl@3.1.0: is-wsl@3.1.0:
resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==}
engines: {node: '>=16'} engines: {node: '>=16'}
@ -1285,9 +1416,21 @@ packages:
resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
linkify-it@5.0.0:
resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
lodash.castarray@4.4.0:
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
lodash.debounce@4.0.8: lodash.debounce@4.0.8:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
longest-streak@3.1.0: longest-streak@3.1.0:
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
@ -1303,6 +1446,10 @@ packages:
magicast@0.3.5: magicast@0.3.5:
resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==}
markdown-it@14.1.0:
resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
hasBin: true
markdown-table@3.0.4: markdown-table@3.0.4:
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
@ -1348,6 +1495,9 @@ packages:
mdn-data@2.12.2: mdn-data@2.12.2:
resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==}
mdurl@2.0.0:
resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
micromark-core-commonmark@2.0.3: micromark-core-commonmark@2.0.3:
resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==}
@ -1519,6 +1669,9 @@ packages:
parse-latin@7.0.0: parse-latin@7.0.0:
resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==} resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==}
parse-srcset@1.0.2:
resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==}
parse5@7.3.0: parse5@7.3.0:
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
@ -1533,6 +1686,10 @@ packages:
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
engines: {node: '>=12'} engines: {node: '>=12'}
postcss-selector-parser@6.0.10:
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
engines: {node: '>=4'}
postcss@8.5.6: postcss@8.5.6:
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
@ -1554,6 +1711,10 @@ packages:
proxy-compare@3.0.1: proxy-compare@3.0.1:
resolution: {integrity: sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q==} resolution: {integrity: sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q==}
punycode.js@2.3.1:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
engines: {node: '>=6'}
radix3@1.1.2: radix3@1.1.2:
resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==}
@ -1636,6 +1797,9 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'} engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true hasBin: true
sanitize-html@2.17.0:
resolution: {integrity: sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA==}
scheduler@0.26.0: scheduler@0.26.0:
resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
@ -1743,6 +1907,9 @@ packages:
engines: {node: '>=14.17'} engines: {node: '>=14.17'}
hasBin: true hasBin: true
uc.micro@2.1.0:
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
ufo@1.6.1: ufo@1.6.1:
resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
@ -1794,6 +1961,9 @@ packages:
unist-util-visit@5.0.0: unist-util-visit@5.0.0:
resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
universal-user-agent@7.0.3:
resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==}
unstorage@1.16.1: unstorage@1.16.1:
resolution: {integrity: sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ==} resolution: {integrity: sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ==}
peerDependencies: peerDependencies:
@ -1865,6 +2035,9 @@ packages:
peerDependencies: peerDependencies:
react: ^16.8.0 || ^17 || ^18 || ^19 || ^19.0.0-rc react: ^16.8.0 || ^17 || ^18 || ^19 || ^19.0.0-rc
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
vfile-location@5.0.3: vfile-location@5.0.3:
resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==}
@ -2358,6 +2531,68 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2 '@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.4 '@jridgewell/sourcemap-codec': 1.5.4
'@octokit/auth-token@6.0.0': {}
'@octokit/core@7.0.3':
dependencies:
'@octokit/auth-token': 6.0.0
'@octokit/graphql': 9.0.1
'@octokit/request': 10.0.3
'@octokit/request-error': 7.0.0
'@octokit/types': 14.1.0
before-after-hook: 4.0.0
universal-user-agent: 7.0.3
'@octokit/endpoint@11.0.0':
dependencies:
'@octokit/types': 14.1.0
universal-user-agent: 7.0.3
'@octokit/graphql@9.0.1':
dependencies:
'@octokit/request': 10.0.3
'@octokit/types': 14.1.0
universal-user-agent: 7.0.3
'@octokit/openapi-types@25.1.0': {}
'@octokit/plugin-paginate-rest@13.1.1(@octokit/core@7.0.3)':
dependencies:
'@octokit/core': 7.0.3
'@octokit/types': 14.1.0
'@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.3)':
dependencies:
'@octokit/core': 7.0.3
'@octokit/plugin-rest-endpoint-methods@16.0.0(@octokit/core@7.0.3)':
dependencies:
'@octokit/core': 7.0.3
'@octokit/types': 14.1.0
'@octokit/request-error@7.0.0':
dependencies:
'@octokit/types': 14.1.0
'@octokit/request@10.0.3':
dependencies:
'@octokit/endpoint': 11.0.0
'@octokit/request-error': 7.0.0
'@octokit/types': 14.1.0
fast-content-type-parse: 3.0.0
universal-user-agent: 7.0.3
'@octokit/rest@22.0.0':
dependencies:
'@octokit/core': 7.0.3
'@octokit/plugin-paginate-rest': 13.1.1(@octokit/core@7.0.3)
'@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.3)
'@octokit/plugin-rest-endpoint-methods': 16.0.0(@octokit/core@7.0.3)
'@octokit/types@14.1.0':
dependencies:
'@octokit/openapi-types': 25.1.0
'@oslojs/encoding@1.1.0': {} '@oslojs/encoding@1.1.0': {}
'@rolldown/pluginutils@1.0.0-beta.27': {} '@rolldown/pluginutils@1.0.0-beta.27': {}
@ -2553,6 +2788,14 @@ snapshots:
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.11 '@tailwindcss/oxide-win32-arm64-msvc': 4.1.11
'@tailwindcss/oxide-win32-x64-msvc': 4.1.11 '@tailwindcss/oxide-win32-x64-msvc': 4.1.11
'@tailwindcss/typography@0.5.16(tailwindcss@4.1.11)':
dependencies:
lodash.castarray: 4.4.0
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
postcss-selector-parser: 6.0.10
tailwindcss: 4.1.11
'@tailwindcss/vite@4.1.11(vite@6.3.5(@types/node@24.1.0)(jiti@2.5.1)(lightningcss@1.30.1))': '@tailwindcss/vite@4.1.11(vite@6.3.5(@types/node@24.1.0)(jiti@2.5.1)(lightningcss@1.30.1))':
dependencies: dependencies:
'@tailwindcss/node': 4.1.11 '@tailwindcss/node': 4.1.11
@ -2595,10 +2838,19 @@ snapshots:
dependencies: dependencies:
'@types/unist': 3.0.3 '@types/unist': 3.0.3
'@types/linkify-it@5.0.0': {}
'@types/markdown-it@14.1.2':
dependencies:
'@types/linkify-it': 5.0.0
'@types/mdurl': 2.0.0
'@types/mdast@4.0.4': '@types/mdast@4.0.4':
dependencies: dependencies:
'@types/unist': 3.0.3 '@types/unist': 3.0.3
'@types/mdurl@2.0.0': {}
'@types/ms@2.1.0': {} '@types/ms@2.1.0': {}
'@types/nlcst@2.0.3': '@types/nlcst@2.0.3':
@ -2617,6 +2869,10 @@ snapshots:
dependencies: dependencies:
csstype: 3.1.3 csstype: 3.1.3
'@types/sanitize-html@2.16.0':
dependencies:
htmlparser2: 8.0.2
'@types/unist@3.0.3': {} '@types/unist@3.0.3': {}
'@ungap/structured-clone@1.3.0': {} '@ungap/structured-clone@1.3.0': {}
@ -2928,6 +3184,8 @@ snapshots:
base64-js@1.5.1: {} base64-js@1.5.1: {}
before-after-hook@4.0.0: {}
blob-to-buffer@1.2.9: {} blob-to-buffer@1.2.9: {}
boxen@8.0.1: boxen@8.0.1:
@ -3029,6 +3287,8 @@ snapshots:
csstype@3.1.3: {} csstype@3.1.3: {}
date-fns@4.1.0: {}
debug@4.4.1: debug@4.4.1:
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
@ -3037,6 +3297,8 @@ snapshots:
dependencies: dependencies:
character-entities: 2.0.2 character-entities: 2.0.2
deepmerge@4.3.1: {}
defu@6.1.4: {} defu@6.1.4: {}
dequal@2.0.3: {} dequal@2.0.3: {}
@ -3061,6 +3323,24 @@ snapshots:
dlv@1.1.3: {} dlv@1.1.3: {}
dom-serializer@2.0.0:
dependencies:
domelementtype: 2.3.0
domhandler: 5.0.3
entities: 4.5.0
domelementtype@2.3.0: {}
domhandler@5.0.3:
dependencies:
domelementtype: 2.3.0
domutils@3.2.2:
dependencies:
dom-serializer: 2.0.0
domelementtype: 2.3.0
domhandler: 5.0.3
dset@3.1.4: {} dset@3.1.4: {}
electron-to-chromium@1.5.194: {} electron-to-chromium@1.5.194: {}
@ -3074,6 +3354,8 @@ snapshots:
graceful-fs: 4.2.11 graceful-fs: 4.2.11
tapable: 2.2.2 tapable: 2.2.2
entities@4.5.0: {}
entities@6.0.1: {} entities@6.0.1: {}
es-module-lexer@1.7.0: {} es-module-lexer@1.7.0: {}
@ -3109,6 +3391,8 @@ snapshots:
escalade@3.2.0: {} escalade@3.2.0: {}
escape-string-regexp@4.0.0: {}
escape-string-regexp@5.0.0: {} escape-string-regexp@5.0.0: {}
estree-walker@2.0.2: {} estree-walker@2.0.2: {}
@ -3121,6 +3405,8 @@ snapshots:
extend@3.0.2: {} extend@3.0.2: {}
fast-content-type-parse@3.0.0: {}
fast-deep-equal@3.1.3: {} fast-deep-equal@3.1.3: {}
fdir@6.4.6(picomatch@4.0.3): fdir@6.4.6(picomatch@4.0.3):
@ -3260,6 +3546,13 @@ snapshots:
html-void-elements@3.0.0: {} html-void-elements@3.0.0: {}
htmlparser2@8.0.2:
dependencies:
domelementtype: 2.3.0
domhandler: 5.0.3
domutils: 3.2.2
entities: 4.5.0
http-cache-semantics@4.2.0: {} http-cache-semantics@4.2.0: {}
import-meta-resolve@4.1.0: {} import-meta-resolve@4.1.0: {}
@ -3279,6 +3572,8 @@ snapshots:
is-plain-obj@4.1.0: {} is-plain-obj@4.1.0: {}
is-plain-object@5.0.0: {}
is-wsl@3.1.0: is-wsl@3.1.0:
dependencies: dependencies:
is-inside-container: 1.0.0 is-inside-container: 1.0.0
@ -3344,8 +3639,18 @@ snapshots:
lightningcss-win32-arm64-msvc: 1.30.1 lightningcss-win32-arm64-msvc: 1.30.1
lightningcss-win32-x64-msvc: 1.30.1 lightningcss-win32-x64-msvc: 1.30.1
linkify-it@5.0.0:
dependencies:
uc.micro: 2.1.0
lodash.castarray@4.4.0: {}
lodash.debounce@4.0.8: {} lodash.debounce@4.0.8: {}
lodash.isplainobject@4.0.6: {}
lodash.merge@4.6.2: {}
longest-streak@3.1.0: {} longest-streak@3.1.0: {}
lru-cache@10.4.3: {} lru-cache@10.4.3: {}
@ -3364,6 +3669,15 @@ snapshots:
'@babel/types': 7.28.2 '@babel/types': 7.28.2
source-map-js: 1.2.1 source-map-js: 1.2.1
markdown-it@14.1.0:
dependencies:
argparse: 2.0.1
entities: 4.5.0
linkify-it: 5.0.0
mdurl: 2.0.0
punycode.js: 2.3.1
uc.micro: 2.1.0
markdown-table@3.0.4: {} markdown-table@3.0.4: {}
mdast-util-definitions@6.0.0: mdast-util-definitions@6.0.0:
@ -3488,6 +3802,8 @@ snapshots:
mdn-data@2.12.2: {} mdn-data@2.12.2: {}
mdurl@2.0.0: {}
micromark-core-commonmark@2.0.3: micromark-core-commonmark@2.0.3:
dependencies: dependencies:
decode-named-character-reference: 1.2.0 decode-named-character-reference: 1.2.0
@ -3751,6 +4067,8 @@ snapshots:
unist-util-visit-children: 3.0.0 unist-util-visit-children: 3.0.0
vfile: 6.0.3 vfile: 6.0.3
parse-srcset@1.0.2: {}
parse5@7.3.0: parse5@7.3.0:
dependencies: dependencies:
entities: 6.0.1 entities: 6.0.1
@ -3761,6 +4079,11 @@ snapshots:
picomatch@4.0.3: {} picomatch@4.0.3: {}
postcss-selector-parser@6.0.10:
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
postcss@8.5.6: postcss@8.5.6:
dependencies: dependencies:
nanoid: 3.3.11 nanoid: 3.3.11
@ -3780,6 +4103,8 @@ snapshots:
proxy-compare@3.0.1: {} proxy-compare@3.0.1: {}
punycode.js@2.3.1: {}
radix3@1.1.2: {} radix3@1.1.2: {}
react-dom@19.1.1(react@19.1.1): react-dom@19.1.1(react@19.1.1):
@ -3926,6 +4251,15 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.46.2 '@rollup/rollup-win32-x64-msvc': 4.46.2
fsevents: 2.3.3 fsevents: 2.3.3
sanitize-html@2.17.0:
dependencies:
deepmerge: 4.3.1
escape-string-regexp: 4.0.0
htmlparser2: 8.0.2
is-plain-object: 5.0.0
parse-srcset: 1.0.2
postcss: 8.5.6
scheduler@0.26.0: {} scheduler@0.26.0: {}
semver@6.3.1: {} semver@6.3.1: {}
@ -4046,6 +4380,8 @@ snapshots:
typescript@5.9.2: {} typescript@5.9.2: {}
uc.micro@2.1.0: {}
ufo@1.6.1: {} ufo@1.6.1: {}
ultrahtml@1.6.0: {} ultrahtml@1.6.0: {}
@ -4122,6 +4458,8 @@ snapshots:
unist-util-is: 6.0.0 unist-util-is: 6.0.0
unist-util-visit-parents: 6.0.1 unist-util-visit-parents: 6.0.1
universal-user-agent@7.0.3: {}
unstorage@1.16.1: unstorage@1.16.1:
dependencies: dependencies:
anymatch: 3.1.3 anymatch: 3.1.3
@ -4144,6 +4482,8 @@ snapshots:
lodash.debounce: 4.0.8 lodash.debounce: 4.0.8
react: 19.1.1 react: 19.1.1
util-deprecate@1.0.2: {}
vfile-location@5.0.3: vfile-location@5.0.3:
dependencies: dependencies:
'@types/unist': 3.0.3 '@types/unist': 3.0.3

View File

@ -1,4 +1,5 @@
--- ---
import { FaGithub } from "react-icons/fa6";
import "../styles/global.css"; import "../styles/global.css";
import TopBar from "~/components/navigation/TopBar.astro"; import TopBar from "~/components/navigation/TopBar.astro";
--- ---
@ -11,10 +12,52 @@ import TopBar from "~/components/navigation/TopBar.astro";
<link rel="icon" href="/favicon.ico" type="image/x-icon" /> <link rel="icon" href="/favicon.ico" type="image/x-icon" />
<meta name="generator" content={Astro.generator} /> <meta name="generator" content={Astro.generator} />
<title>Spotube</title> <title>Spotube</title>
<meta
name="description"
content="An Open Source Music Client for every platform"
/>
<meta
name="keywords"
content="music, client, open source, music, streaming"
/>
<meta name="author" content="KRTirtho" />
<meta name="robots" content="index, follow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#1DB954" />
</head> </head>
<body> <body>
<main class="p-2 md:p-4 min-h-[90vh]">
<TopBar /> <TopBar />
<slot /> <slot />
</main>
<footer class="w-full bg-tertiary-100-900 p-4 flex justify-between">
<div>
<h3 class="h3">Spotube</h3>
<p>
Copyright © {new Date().getFullYear()} Spotube
</p>
</div>
<ul>
<li>
<a href="https://github.com/KRTirtho/spotube">
<FaGithub className="inline mr-1" />
Github
</a>
</li>
<li>
<a href="https://opencollective.org/spotube">
<img
src="https://avatars0.githubusercontent.com/u/13403593?v=4"
alt="OpenCollective"
height="20"
width="20"
class="inline mr-1"
/>
OpenCollective
</a>
</li>
</ul>
</footer>
</body> </body>
</html> </html>

View File

@ -0,0 +1,33 @@
---
import type { IconType } from "react-icons";
interface Props {
links: Record<string, [string, IconType[], string]>;
}
const { links } = Astro.props;
---
<div class="grid sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
{
Object.entries(links).map((link) => {
return (
<a
href={link[1][0]}
class="flex flex-col btn preset-tonal-secondary rounded-xl p-0 overflow-hidden"
>
<div class="relative bg-primary-500 p-4 flex gap-4 justify-center rounded-t-xl w-full">
{link[1][1].map((icon) => {
const Icon = icon;
return <Icon />;
})}
<p class="chip preset-tonal-warning text-warning-400 absolute right-2 uppercase">
{link[1][2]}
</p>
</div>
<p class="p-4">{link[0]}</p>
</a>
);
})
}
</div>

View File

@ -0,0 +1,39 @@
import type { RestEndpointMethodTypes } from "@octokit/rest";
import { LuBook, LuChevronDown, LuChevronUp } from "react-icons/lu";
import markdownIt from "markdown-it";
import sanitizeHtml from "sanitize-html";
interface Props {
release: RestEndpointMethodTypes["repos"]["getReleaseByTag"]["response"]["data"];
}
export default function ReleaseBody({ release }: Props) {
const summary = "Release Notes & Changelogs";
const body = release.body ?? "No release notes available.";
const md = markdownIt({
html: true,
linkify: true,
typographer: true,
});
const sanitizedBody = sanitizeHtml(md.render(body));
return (<details className="rounded-md p-4 my-4 preset-tonal-primary group">
<summary className="flex items-center cursor-pointer font-semibold text-lg gap-2">
<LuBook className="inline" />
{summary}
<span className="ml-auto flex items-center">
<span className="block group-open:hidden">
<LuChevronDown />
</span>
<span className="hidden group-open:block">
<LuChevronUp />
</span>
</span>
</summary>
<article
className="prose lg:prose-xl dark:prose-invert"
dangerouslySetInnerHTML={{ __html: sanitizedBody }}
/>
</details>)
}

View File

@ -0,0 +1,178 @@
import { formatDistanceToNow, formatRelative } from "date-fns";
import ReleaseBody from "~/modules/downloads/older/release-body";
import RootLayout from "~/layouts/RootLayout.astro";
import { Octokit, type RestEndpointMethodTypes } from "@octokit/rest";
import {
FaAndroid,
FaApple,
FaGit,
FaGooglePlay,
FaLinux,
FaWindows,
} from "react-icons/fa6";
import type { IconType } from "react-icons";
import { useEffect, useState } from "react";
function getIcon(assetUrl: string) {
assetUrl = assetUrl.toLowerCase();
if (assetUrl.includes("linux")) return FaLinux;
if (assetUrl.includes("windows")) return FaWindows;
if (assetUrl.includes("mac")) return FaApple;
if (assetUrl.includes("android")) return FaAndroid;
if (assetUrl.includes("playstore")) return FaGooglePlay;
if (assetUrl.includes("ios")) return FaApple;
return FaGit;
}
function formatName(assetName: string) {
// format the assetName to be
// {OS} ({package extension})
const lowerCasedAssetName = assetName.toLowerCase();
const extension = assetName.split(".").at(-1);
if (lowerCasedAssetName.includes("linux")) {
if (lowerCasedAssetName.includes("aarch64")) {
return [`Linux`, extension, `ARM64`]
}
return [`Linux`, extension, `x64`]
};
if (lowerCasedAssetName.includes("windows")) return [`Windows`, extension];
if (lowerCasedAssetName.includes("mac")) return [`macOS`, extension];
if (
lowerCasedAssetName.includes("android") ||
lowerCasedAssetName.includes("playstore")
)
return [`Android`, extension];
if (lowerCasedAssetName.includes("ios")) return [`iOS`, extension];
return [assetName.replace(`.${extension}`, ""), extension];
}
type OctokitAsset =
RestEndpointMethodTypes["repos"]["listReleases"]["response"]["data"][0]["assets"][0];
function groupByOS(downloads: OctokitAsset[]) {
return downloads.reduce(
(acc, val) => {
const lowName = val.name.toLowerCase();
if (lowName.includes("android") || lowName.includes("playstore"))
acc["android"] = [...(acc.android ?? []), val];
if (lowName.includes("linux"))
acc["linux"] = [...(acc["linux"] ?? []), val];
if (lowName.includes("windows"))
acc["windows"] = [...(acc["windows"] ?? []), val];
if (lowName.includes("ios")) acc["ios"] = [...(acc["ios"] ?? []), val];
if (lowName.includes("mac")) acc["mac"] = [...(acc["mac"] ?? []), val];
return acc;
},
{} as Record<
"android" | "ios" | "mac" | "linux" | "windows",
OctokitAsset[]
>
);
}
const icons: Record<string, [IconType, string]> = {
android: [FaAndroid, "#3DDC84"],
mac: [FaApple, ""],
ios: [FaApple, ""],
linux: [FaLinux, "#000000"],
windows: [FaWindows, "#0078D7"],
};
export default function ReleasesSection() {
const github = new Octokit();
const [releases, setReleases] = useState<RestEndpointMethodTypes["repos"]["listReleases"]["response"]["data"]>([]);
useEffect(() => {
github.repos.listReleases({
owner: "KRTirtho",
repo: "spotube",
}).then((res) => {
setReleases(res.data);
})
}, [])
return <>
{
releases.map((release) => {
return (
<div>
<h4
className="h4"
title={formatRelative(
release.published_at ?? new Date(),
new Date()
)}
>
{release.tag_name}
<span className="text-sm font-normal">
(
{formatDistanceToNow(release.published_at ?? new Date(), {
addSuffix: true,
})}
)
</span>
</h4>
<div className="flex flex-col gap-5">
{Object.entries(groupByOS(release.assets)).map(
([osName, assets]) => {
const Icon = icons[osName][0];
return (
<div className="flex flex-col gap-4">
<h5 className="h5 capitalize">
<Icon className="inline" color={icons[osName][1]} />
{osName}
</h5>
<div className="flex flex-wrap gap-4">
{assets.map((asset) => {
const Icon = getIcon(asset.browser_download_url);
const formattedName = formatName(asset.name);
return (
<a href={asset.browser_download_url}>
<button className="btn preset-tonal-primary rounded p-0 flex flex-col">
<span className="bg-primary-500 rounded-t p-3 w-full">
<Icon className="inline" />
</span>
<span className="p-4 space-x-1">
<span>
{formattedName[0]}
</span>
<span className="chip preset-tonal-error">
{formattedName[1]}
</span>
{
formattedName[2] ?
<span className="chip preset-tonal-error">
{formattedName[2]}
</span> : <></>
}
</span>
</button>
</a>
);
})}
</div>
</div>
);
}
)}
</div>
<ReleaseBody release={release} />
<hr />
</div>
);
})
}
</>
}

View File

@ -0,0 +1,80 @@
import { useEffect, useState } from "react";
import { Avatar } from "@skeletonlabs/skeleton-react";
interface Member {
MemberId: number;
createdAt: string;
type: string;
role: string;
isActive: boolean;
totalAmountDonated: number;
currency?: string;
lastTransactionAt: string;
lastTransactionAmount: number;
profile: string;
name: string;
company?: string;
description?: string;
image?: string;
email?: string;
twitter?: string;
github?: string;
website?: string;
tier?: string;
}
const formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
compactDisplay: 'short',
maximumFractionDigits: 0
});
export function Supporters() {
const [members, setMembers] = useState<Member[]>([]);
useEffect(() => {
// Fetch members data from an API or other source
async function fetchMembers() {
const res = await fetch('https://opencollective.com/spotube/members/all.json');
const members = (await res.json()) as Member[];
setMembers(
members
.filter((m) => m.totalAmountDonated > 0)
.sort((a, b) => b.totalAmountDonated - a.totalAmountDonated)
);
};
fetchMembers();
}, []);
return <div
className="gap-4 grid"
style={{
gridTemplateColumns: 'repeat(auto-fill, minmax(150px, 1fr))',
gridAutoRows: 'minmax(50px, auto)',
}}
>
{
members.map((member) => {
return <a
key={member.MemberId}
href={member.profile}
target="_blank"
className="flex items-center gap-2 px-2 py-1 overflow-ellipsis preset-tonal-secondary rounded-lg"
>
<Avatar src={member.image} name={member.name} classes="w-10 h-10" />
<div className="flex flex-col overflow-hidden">
<p className="truncate">{member.name}</p>
<p className="capitalize text-sm underline decoration-dotted">
{formatter.format(member.totalAmountDonated)}
({member.role.toLowerCase()})
</p>
</div>
</a>;
})
}
</div>;
}

View File

@ -1,5 +1,53 @@
--- ---
import type { IconType } from "react-icons";
import { LuDownload, LuHistory, LuPackage, LuSparkles } from "react-icons/lu";
import { extendedDownloadLinks } from "~/collections/app";
import RootLayout from "~/layouts/RootLayout.astro"; import RootLayout from "~/layouts/RootLayout.astro";
import DownloadItems from "~/modules/downloads/download-item.astro";
const otherDownloads: [string, string, IconType][] = [
["/downloads/packages", "CLI Packages Managers", LuPackage],
["/downloads/older", "Older Versions", LuHistory],
["/downloads/nightly", "Nightly Builds", LuSparkles],
];
--- ---
<RootLayout /> <RootLayout>
<section class="p-4 md:p-16 md:pb-4">
<h2 class="h2 flex items-center gap-4">
Download
<LuDownload className="inline" size={30} />
</h2>
<br /><br />
<h5 class="h5">Spotube is available for every platform</h5>
<br />
<DownloadItems links={extendedDownloadLinks} />
<br />
<br />
<!-- <Ads adSlot={ADS_SLOTS.downloadPageDisplay} adFormat="auto" /> -->
<br />
<h2 class="h2">Other Downloads</h2>
<br /><br />
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-2 max-w-3xl">
{
otherDownloads.map((download) => {
const Icon = download[2];
return (
<a href={download[0]}>
<div class="btn preset-tonal-secondary flex flex-col items-center p-4 gap-4">
<Icon />
<h5 class="h5">{download[1]}</h5>
</div>
</a>
);
})
}
</div>
<br />
<!-- <Ads adSlot={ADS_SLOTS.downloadPageDisplay} adFormat="auto" /> -->
</section>
</RootLayout>

View File

@ -0,0 +1,47 @@
---
import { LuBug, LuSparkles, LuTriangleAlert } from "react-icons/lu";
import { extendedNightlyDownloadLinks } from "~/collections/app";
import RootLayout from "~/layouts/RootLayout.astro";
import DownloadItems from "~/modules/downloads/download-item.astro";
---
<RootLayout>
<section class="p-4 md:p-16">
<h2 class="h2 flex items-center gap-4">
Nightly Downloads
<LuSparkles className="inline" size={30} />
</h2>
<br /><br />
<aside class="preset-tonal-warning rounded-xl">
<div class="h3 pl-4 pt-4">
<LuTriangleAlert className="text-warning-500" />
</div>
<div class="p-4">
<h3 class="h3">
Nightly versions may contain bugs <LuBug className="inline" />
</h3>
<p>
Although Nightly versions are packed with newest and greatest
features, it's often unstable and not tested by the maintainers and
publisher(s).
<br />
<span class="text-error-500 underline decoration-dotted">
So use it at your own risk.
</span>
<span>
Go to <a href="/downloads" class="anchor">Downloads</a> for more stable
releases.
</span>
</p>
</div>
</aside>
<br />
<p class="mb-4">Following are the new v5 Nightly versions:</p>
<DownloadItems links={extendedNightlyDownloadLinks} />
<br />
<!-- <Ads adSlot={ADS_SLOTS.downloadPageDisplay} adFormat="auto" /> -->
<br />
</section>
</RootLayout>

View File

@ -0,0 +1,12 @@
---
import RootLayout from "~/layouts/RootLayout.astro";
import ReleasesSection from "~/modules/downloads/older/releases";
---
<RootLayout>
<div class="p-4 md:p-24">
<div class="flex flex-col gap-5">
<ReleasesSection client:only />
</div>
</div>
</RootLayout>

View File

@ -0,0 +1,5 @@
---
import RootLayout from "~/layouts/RootLayout.astro";
---
<RootLayout />

View File

@ -1,5 +1,78 @@
--- ---
import { FaAndroid, FaApple, FaLinux, FaWindows } from "react-icons/fa6";
import RootLayout from "../layouts/RootLayout.astro"; import RootLayout from "../layouts/RootLayout.astro";
import { LuHeart } from "react-icons/lu";
import { Supporters } from "~/modules/root/supporters";
--- ---
<RootLayout /> <RootLayout>
<section class="ps-4 pt-16 md:ps-24 md:pt-24">
<div class="flex flex-col gap-4">
<div>
<h1 class="h1">Spotube</h1>
<br />
<h3 class="h3">
A cross-platform Extensible open-source Music Streaming platform
<div class="inline-flex gap-3 items-center">
<FaAndroid className="inline text-[#3DDC84]" />
<FaWindows className="inline text-[#00A2F0]" />
<FaLinux className="inline" />
<FaApple className="inline" />
</div>
</h3>
<p class="text-surface-500">
And it's <span class="text-error-500 underline decoration-dashed"
>not</span
>
built with Electron (web technologies)
</p>
<br />
<div class="flex items-center gap-3">
<a
href="https://news.ycombinator.com/item?id=39066136"
target="_blank"
>
<img
src="https://hackerbadge.vercel.app/api?id=39066136"
alt="HackerNews"
/>
</a>
<!-- <a href="https://flathub.org/apps/com.github.KRTirtho.Spotube" target="_blank">
<img
width="160"
alt="Download on Flathub"
src="https://flathub.org/api/badge?locale=en"
/>
</a> -->
</div>
</div>
</div>
<br />
<!-- <Ads adSlot={ADS_SLOTS.rootPageDisplay} adFormat="auto" /> -->
<br />
<div class="flex flex-col gap-4">
<h2 class="h2">
Supporters
<LuHeart className="inline-block" color="red" />
</h2>
<p class="text-surface-500">
We are grateful for the support of individuals and organizations who
have made Spotube possible.
</p>
<div class="flex justify-center">
<a href="https://opencollective.com/spotube/donate" target="_blank">
<img
src="https://opencollective.com/webpack/donate/button@2x.png?color=blue"
width="300"
alt="Open Collective"
/>
</a>
</div>
<Supporters client:only />
</div>
<br />
<!-- <Ads adSlot={ADS_SLOTS.rootPageDisplay} adFormat="auto" /> -->
</section>
</RootLayout>

View File

@ -1,4 +1,5 @@
@import "tailwindcss"; @import "tailwindcss";
@plugin "@tailwindcss/typography";
@source '../../node_modules/@skeletonlabs/skeleton-react/dist'; @source '../../node_modules/@skeletonlabs/skeleton-react/dist';

View File

@ -16,5 +16,7 @@
], ],
}, },
"baseUrl": "./src", "baseUrl": "./src",
"module": "node16",
"moduleResolution": "node16"
} }
} }