mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
website: add downloads pages
This commit is contained in:
parent
49e2d1b759
commit
7a630507fb
@ -10,18 +10,25 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/react": "^4.3.0",
|
||||
"@octokit/rest": "^22.0.0",
|
||||
"@skeletonlabs/skeleton-react": "^1.2.4",
|
||||
"@tailwindcss/vite": "^4.1.11",
|
||||
"@types/react": "^19.1.9",
|
||||
"@types/react-dom": "^19.1.7",
|
||||
"astro": "^5.12.8",
|
||||
"date-fns": "^4.1.0",
|
||||
"markdown-it": "^14.1.0",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-icons": "^5.5.0",
|
||||
"sanitize-html": "^2.17.0",
|
||||
"tailwindcss": "^4.1.11",
|
||||
"usehooks-ts": "^3.1.1"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
@ -11,6 +11,9 @@ importers:
|
||||
'@astrojs/react':
|
||||
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)
|
||||
'@octokit/rest':
|
||||
specifier: ^22.0.0
|
||||
version: 22.0.0
|
||||
'@skeletonlabs/skeleton-react':
|
||||
specifier: ^1.2.4
|
||||
version: 1.2.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
@ -26,6 +29,12 @@ importers:
|
||||
astro:
|
||||
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)
|
||||
date-fns:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0
|
||||
markdown-it:
|
||||
specifier: ^14.1.0
|
||||
version: 14.1.0
|
||||
react:
|
||||
specifier: ^19.1.1
|
||||
version: 19.1.1
|
||||
@ -35,6 +44,9 @@ importers:
|
||||
react-icons:
|
||||
specifier: ^5.5.0
|
||||
version: 5.5.0(react@19.1.1)
|
||||
sanitize-html:
|
||||
specifier: ^2.17.0
|
||||
version: 2.17.0
|
||||
tailwindcss:
|
||||
specifier: ^4.1.11
|
||||
version: 4.1.11
|
||||
@ -45,6 +57,15 @@ importers:
|
||||
'@skeletonlabs/skeleton':
|
||||
specifier: ^3.1.7
|
||||
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:
|
||||
|
||||
@ -445,6 +466,58 @@ packages:
|
||||
'@jridgewell/trace-mapping@0.3.29':
|
||||
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':
|
||||
resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==}
|
||||
|
||||
@ -680,6 +753,11 @@ packages:
|
||||
resolution: {integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==}
|
||||
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':
|
||||
resolution: {integrity: sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==}
|
||||
peerDependencies:
|
||||
@ -709,9 +787,18 @@ packages:
|
||||
'@types/hast@3.0.4':
|
||||
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':
|
||||
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
|
||||
|
||||
'@types/mdurl@2.0.0':
|
||||
resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==}
|
||||
|
||||
'@types/ms@2.1.0':
|
||||
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
||||
|
||||
@ -729,6 +816,9 @@ packages:
|
||||
'@types/react@19.1.9':
|
||||
resolution: {integrity: sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA==}
|
||||
|
||||
'@types/sanitize-html@2.16.0':
|
||||
resolution: {integrity: sha512-l6rX1MUXje5ztPT0cAFtUayXF06DqPhRyfVXareEN5gGCFaP/iwsxIyKODr9XDhfxPpN6vXUFNfo5kZMXCxBtw==}
|
||||
|
||||
'@types/unist@3.0.3':
|
||||
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
|
||||
|
||||
@ -874,6 +964,9 @@ packages:
|
||||
base64-js@1.5.1:
|
||||
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:
|
||||
resolution: {integrity: sha512-BF033y5fN6OCofD3vgHmNtwZWRcq9NLyyxyILx9hfMy1sXYy4ojFl765hJ2lP0YaN2fuxPaLO2Vzzoxy0FLFFA==}
|
||||
|
||||
@ -984,6 +1077,9 @@ packages:
|
||||
csstype@3.1.3:
|
||||
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||
|
||||
date-fns@4.1.0:
|
||||
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
|
||||
|
||||
debug@4.4.1:
|
||||
resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
|
||||
engines: {node: '>=6.0'}
|
||||
@ -996,6 +1092,10 @@ packages:
|
||||
decode-named-character-reference@1.2.0:
|
||||
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:
|
||||
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
|
||||
|
||||
@ -1030,6 +1130,19 @@ packages:
|
||||
dlv@1.1.3:
|
||||
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:
|
||||
resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==}
|
||||
engines: {node: '>=4'}
|
||||
@ -1047,6 +1160,10 @@ packages:
|
||||
resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
entities@4.5.0:
|
||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
entities@6.0.1:
|
||||
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
|
||||
engines: {node: '>=0.12'}
|
||||
@ -1063,6 +1180,10 @@ packages:
|
||||
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
escape-string-regexp@4.0.0:
|
||||
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
escape-string-regexp@5.0.0:
|
||||
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
||||
engines: {node: '>=12'}
|
||||
@ -1079,6 +1200,9 @@ packages:
|
||||
extend@3.0.2:
|
||||
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:
|
||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||
|
||||
@ -1158,6 +1282,9 @@ packages:
|
||||
html-void-elements@3.0.0:
|
||||
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
|
||||
|
||||
htmlparser2@8.0.2:
|
||||
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
|
||||
|
||||
http-cache-semantics@4.2.0:
|
||||
resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==}
|
||||
|
||||
@ -1188,6 +1315,10 @@ packages:
|
||||
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
is-plain-object@5.0.0:
|
||||
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-wsl@3.1.0:
|
||||
resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==}
|
||||
engines: {node: '>=16'}
|
||||
@ -1285,9 +1416,21 @@ packages:
|
||||
resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
|
||||
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:
|
||||
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:
|
||||
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
|
||||
|
||||
@ -1303,6 +1446,10 @@ packages:
|
||||
magicast@0.3.5:
|
||||
resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==}
|
||||
|
||||
markdown-it@14.1.0:
|
||||
resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
|
||||
hasBin: true
|
||||
|
||||
markdown-table@3.0.4:
|
||||
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
|
||||
|
||||
@ -1348,6 +1495,9 @@ packages:
|
||||
mdn-data@2.12.2:
|
||||
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:
|
||||
resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==}
|
||||
|
||||
@ -1519,6 +1669,9 @@ packages:
|
||||
parse-latin@7.0.0:
|
||||
resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==}
|
||||
|
||||
parse-srcset@1.0.2:
|
||||
resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==}
|
||||
|
||||
parse5@7.3.0:
|
||||
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
|
||||
|
||||
@ -1533,6 +1686,10 @@ packages:
|
||||
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
postcss-selector-parser@6.0.10:
|
||||
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
postcss@8.5.6:
|
||||
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
@ -1554,6 +1711,10 @@ packages:
|
||||
proxy-compare@3.0.1:
|
||||
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:
|
||||
resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==}
|
||||
|
||||
@ -1636,6 +1797,9 @@ packages:
|
||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
|
||||
sanitize-html@2.17.0:
|
||||
resolution: {integrity: sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA==}
|
||||
|
||||
scheduler@0.26.0:
|
||||
resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
|
||||
|
||||
@ -1743,6 +1907,9 @@ packages:
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
uc.micro@2.1.0:
|
||||
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
|
||||
|
||||
ufo@1.6.1:
|
||||
resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
|
||||
|
||||
@ -1794,6 +1961,9 @@ packages:
|
||||
unist-util-visit@5.0.0:
|
||||
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:
|
||||
resolution: {integrity: sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ==}
|
||||
peerDependencies:
|
||||
@ -1865,6 +2035,9 @@ packages:
|
||||
peerDependencies:
|
||||
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:
|
||||
resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==}
|
||||
|
||||
@ -2358,6 +2531,68 @@ snapshots:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@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': {}
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.27': {}
|
||||
@ -2553,6 +2788,14 @@ snapshots:
|
||||
'@tailwindcss/oxide-win32-arm64-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))':
|
||||
dependencies:
|
||||
'@tailwindcss/node': 4.1.11
|
||||
@ -2595,10 +2838,19 @@ snapshots:
|
||||
dependencies:
|
||||
'@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':
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
|
||||
'@types/mdurl@2.0.0': {}
|
||||
|
||||
'@types/ms@2.1.0': {}
|
||||
|
||||
'@types/nlcst@2.0.3':
|
||||
@ -2617,6 +2869,10 @@ snapshots:
|
||||
dependencies:
|
||||
csstype: 3.1.3
|
||||
|
||||
'@types/sanitize-html@2.16.0':
|
||||
dependencies:
|
||||
htmlparser2: 8.0.2
|
||||
|
||||
'@types/unist@3.0.3': {}
|
||||
|
||||
'@ungap/structured-clone@1.3.0': {}
|
||||
@ -2928,6 +3184,8 @@ snapshots:
|
||||
|
||||
base64-js@1.5.1: {}
|
||||
|
||||
before-after-hook@4.0.0: {}
|
||||
|
||||
blob-to-buffer@1.2.9: {}
|
||||
|
||||
boxen@8.0.1:
|
||||
@ -3029,6 +3287,8 @@ snapshots:
|
||||
|
||||
csstype@3.1.3: {}
|
||||
|
||||
date-fns@4.1.0: {}
|
||||
|
||||
debug@4.4.1:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
@ -3037,6 +3297,8 @@ snapshots:
|
||||
dependencies:
|
||||
character-entities: 2.0.2
|
||||
|
||||
deepmerge@4.3.1: {}
|
||||
|
||||
defu@6.1.4: {}
|
||||
|
||||
dequal@2.0.3: {}
|
||||
@ -3061,6 +3323,24 @@ snapshots:
|
||||
|
||||
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: {}
|
||||
|
||||
electron-to-chromium@1.5.194: {}
|
||||
@ -3074,6 +3354,8 @@ snapshots:
|
||||
graceful-fs: 4.2.11
|
||||
tapable: 2.2.2
|
||||
|
||||
entities@4.5.0: {}
|
||||
|
||||
entities@6.0.1: {}
|
||||
|
||||
es-module-lexer@1.7.0: {}
|
||||
@ -3109,6 +3391,8 @@ snapshots:
|
||||
|
||||
escalade@3.2.0: {}
|
||||
|
||||
escape-string-regexp@4.0.0: {}
|
||||
|
||||
escape-string-regexp@5.0.0: {}
|
||||
|
||||
estree-walker@2.0.2: {}
|
||||
@ -3121,6 +3405,8 @@ snapshots:
|
||||
|
||||
extend@3.0.2: {}
|
||||
|
||||
fast-content-type-parse@3.0.0: {}
|
||||
|
||||
fast-deep-equal@3.1.3: {}
|
||||
|
||||
fdir@6.4.6(picomatch@4.0.3):
|
||||
@ -3260,6 +3546,13 @@ snapshots:
|
||||
|
||||
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: {}
|
||||
|
||||
import-meta-resolve@4.1.0: {}
|
||||
@ -3279,6 +3572,8 @@ snapshots:
|
||||
|
||||
is-plain-obj@4.1.0: {}
|
||||
|
||||
is-plain-object@5.0.0: {}
|
||||
|
||||
is-wsl@3.1.0:
|
||||
dependencies:
|
||||
is-inside-container: 1.0.0
|
||||
@ -3344,8 +3639,18 @@ snapshots:
|
||||
lightningcss-win32-arm64-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.isplainobject@4.0.6: {}
|
||||
|
||||
lodash.merge@4.6.2: {}
|
||||
|
||||
longest-streak@3.1.0: {}
|
||||
|
||||
lru-cache@10.4.3: {}
|
||||
@ -3364,6 +3669,15 @@ snapshots:
|
||||
'@babel/types': 7.28.2
|
||||
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: {}
|
||||
|
||||
mdast-util-definitions@6.0.0:
|
||||
@ -3488,6 +3802,8 @@ snapshots:
|
||||
|
||||
mdn-data@2.12.2: {}
|
||||
|
||||
mdurl@2.0.0: {}
|
||||
|
||||
micromark-core-commonmark@2.0.3:
|
||||
dependencies:
|
||||
decode-named-character-reference: 1.2.0
|
||||
@ -3751,6 +4067,8 @@ snapshots:
|
||||
unist-util-visit-children: 3.0.0
|
||||
vfile: 6.0.3
|
||||
|
||||
parse-srcset@1.0.2: {}
|
||||
|
||||
parse5@7.3.0:
|
||||
dependencies:
|
||||
entities: 6.0.1
|
||||
@ -3761,6 +4079,11 @@ snapshots:
|
||||
|
||||
picomatch@4.0.3: {}
|
||||
|
||||
postcss-selector-parser@6.0.10:
|
||||
dependencies:
|
||||
cssesc: 3.0.0
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
postcss@8.5.6:
|
||||
dependencies:
|
||||
nanoid: 3.3.11
|
||||
@ -3780,6 +4103,8 @@ snapshots:
|
||||
|
||||
proxy-compare@3.0.1: {}
|
||||
|
||||
punycode.js@2.3.1: {}
|
||||
|
||||
radix3@1.1.2: {}
|
||||
|
||||
react-dom@19.1.1(react@19.1.1):
|
||||
@ -3926,6 +4251,15 @@ snapshots:
|
||||
'@rollup/rollup-win32-x64-msvc': 4.46.2
|
||||
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: {}
|
||||
|
||||
semver@6.3.1: {}
|
||||
@ -4046,6 +4380,8 @@ snapshots:
|
||||
|
||||
typescript@5.9.2: {}
|
||||
|
||||
uc.micro@2.1.0: {}
|
||||
|
||||
ufo@1.6.1: {}
|
||||
|
||||
ultrahtml@1.6.0: {}
|
||||
@ -4122,6 +4458,8 @@ snapshots:
|
||||
unist-util-is: 6.0.0
|
||||
unist-util-visit-parents: 6.0.1
|
||||
|
||||
universal-user-agent@7.0.3: {}
|
||||
|
||||
unstorage@1.16.1:
|
||||
dependencies:
|
||||
anymatch: 3.1.3
|
||||
@ -4144,6 +4482,8 @@ snapshots:
|
||||
lodash.debounce: 4.0.8
|
||||
react: 19.1.1
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
vfile-location@5.0.3:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
|
@ -1,4 +1,5 @@
|
||||
---
|
||||
import { FaGithub } from "react-icons/fa6";
|
||||
import "../styles/global.css";
|
||||
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" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<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>
|
||||
<body>
|
||||
<main class="p-2 md:p-4 min-h-[90vh]">
|
||||
<TopBar />
|
||||
<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>
|
||||
</html>
|
||||
|
||||
|
33
website/src/modules/downloads/download-item.astro
Normal file
33
website/src/modules/downloads/download-item.astro
Normal 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>
|
39
website/src/modules/downloads/older/release-body.tsx
Normal file
39
website/src/modules/downloads/older/release-body.tsx
Normal 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>)
|
||||
}
|
178
website/src/modules/downloads/older/releases.tsx
Normal file
178
website/src/modules/downloads/older/releases.tsx
Normal 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>
|
||||
);
|
||||
})
|
||||
}
|
||||
</>
|
||||
}
|
80
website/src/modules/root/supporters.tsx
Normal file
80
website/src/modules/root/supporters.tsx
Normal 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>;
|
||||
}
|
@ -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 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>
|
||||
|
47
website/src/pages/downloads/nightly/index.astro
Normal file
47
website/src/pages/downloads/nightly/index.astro
Normal 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>
|
12
website/src/pages/downloads/older/index.astro
Normal file
12
website/src/pages/downloads/older/index.astro
Normal 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>
|
5
website/src/pages/downloads/packages/index.astro
Normal file
5
website/src/pages/downloads/packages/index.astro
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
import RootLayout from "~/layouts/RootLayout.astro";
|
||||
---
|
||||
|
||||
<RootLayout />
|
@ -1,5 +1,78 @@
|
||||
---
|
||||
import { FaAndroid, FaApple, FaLinux, FaWindows } from "react-icons/fa6";
|
||||
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>
|
||||
|
@ -1,4 +1,5 @@
|
||||
@import "tailwindcss";
|
||||
@plugin "@tailwindcss/typography";
|
||||
|
||||
@source '../../node_modules/@skeletonlabs/skeleton-react/dist';
|
||||
|
||||
|
@ -16,5 +16,7 @@
|
||||
],
|
||||
},
|
||||
"baseUrl": "./src",
|
||||
"module": "node16",
|
||||
"moduleResolution": "node16"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user