1
0

add: the full song page UI

This commit is contained in:
alikia2x (寒寒) 2025-09-06 03:11:37 +08:00
parent 337fc072ff
commit 909e9ae48a
43 changed files with 2883 additions and 2221 deletions

108
bun.lock
View File

@ -71,12 +71,11 @@
"packages/solid": {
"name": "solid",
"dependencies": {
"@m3-components/solid": "0.2.2",
"@m3-components/solid": "0.2.6",
"@solid-primitives/media": "^2.3.3",
"@solidjs/meta": "^0.29.4",
"@solidjs/router": "^0.15.3",
"@solidjs/start": "^1.1.7",
"@tailwindcss/vite": "^4.1.11",
"@types/luxon": "^3.7.1",
"@ungap/has-own": "^0.1.1",
"animejs": "^4.1.2",
@ -88,7 +87,7 @@
"postgres": "^3.4.7",
"solid-js": "^1.9.8",
"tailwind-variants": "^1.0.0",
"tailwindcss": "^4.1.11",
"tailwindcss": "3",
"vinxi": "^0.5.8",
},
"devDependencies": {
@ -96,6 +95,7 @@
"@csstools/postcss-cascade-layers": "^5.0.2",
"@csstools/postcss-oklab-function": "^4.0.10",
"@tailwindcss/postcss": "^4.1.11",
"autoprefixer": "^10.4.21",
"drizzle-kit": "^0.31.4",
"postcss": "^8.5.6",
"tsx": "^4.20.3",
@ -349,7 +349,7 @@
"@koshnic/ratelimit": ["@koshnic/ratelimit@1.0.3", "", { "dependencies": { "@types/chai": "^4.3.9", "@types/mocha": "^10.0.3", "chai": "^4.3.10", "ioredis": "^5.3.2", "mocha": "^10.2.0" } }, "sha512-cfDcSc+I+M4hNM+/4M+lfn8UuTq4OEFKl78ThOcGNaO7g8tWb1vm2qVpV1p1loYao1mqk00NBNwHQu2E/qFq2g=="],
"@m3-components/solid": ["@m3-components/solid@0.2.2", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "animejs": "^4.0.2", "solid-js": "^1.9.5", "tailwind-variants": "^1.0.0" } }, "sha512-VRIxWCvBwTbVvf52aTG7BzRHaqAVeIoVeF0ZIUsBDski7Py9QailOPIcBJfL9YtQdVT1umE8xI3hKHnYDnB0jQ=="],
"@m3-components/solid": ["@m3-components/solid@0.2.6", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "animejs": "^4.0.2", "solid-js": "^1.9.5", "tailwind-variants": "^1.0.0" } }, "sha512-NAVhgMcdEMnXV7IPoqVT7kuV6aknGYq/VSAmE7WyvkcF2ITykKrsTQBYHbcIUNO2h72bl7CugboKBRUI0ivUgQ=="],
"@mapbox/node-pre-gyp": ["@mapbox/node-pre-gyp@2.0.0", "", { "dependencies": { "consola": "^3.2.3", "detect-libc": "^2.0.0", "https-proxy-agent": "^7.0.5", "node-fetch": "^2.6.7", "nopt": "^8.0.0", "semver": "^7.5.3", "tar": "^7.4.0" }, "bin": { "node-pre-gyp": "bin/node-pre-gyp" } }, "sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg=="],
@ -569,8 +569,6 @@
"@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.11", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.11", "@tailwindcss/oxide": "4.1.11", "postcss": "^8.4.41", "tailwindcss": "4.1.11" } }, "sha512-q/EAIIpF6WpLhKEuQSEVMZNMIY8KhWoAemZ9eylNAih9jxMGAYPPWBn3I9QL/2jZ+e7OEz/tZkX5HwbBR4HohA=="],
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.11", "", { "dependencies": { "@tailwindcss/node": "4.1.11", "@tailwindcss/oxide": "4.1.11", "tailwindcss": "4.1.11" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw=="],
"@tanstack/directive-functions-plugin": ["@tanstack/directive-functions-plugin@1.121.21", "", { "dependencies": { "@babel/code-frame": "7.26.2", "@babel/core": "^7.26.8", "@babel/traverse": "^7.26.8", "@babel/types": "^7.26.8", "@tanstack/router-utils": "^1.121.21", "babel-dead-code-elimination": "^1.0.10", "tiny-invariant": "^1.3.3" }, "peerDependencies": { "vite": ">=6.0.0" } }, "sha512-B9z/HbF7gJBaRHieyX7f2uQ4LpLLAVAEutBZipH6w+CYD6RHRJvSVPzECGHF7icFhNWTiJQL2QR6K07s59yzEw=="],
"@tanstack/router-utils": ["@tanstack/router-utils@1.121.21", "", { "dependencies": { "@babel/core": "^7.27.4", "@babel/generator": "^7.27.5", "@babel/parser": "^7.27.5", "@babel/preset-typescript": "^7.27.1", "ansis": "^4.1.0", "diff": "^8.0.2" } }, "sha512-u7ubq1xPBtNiU7Fm+EOWlVWdgFLzuKOa1thhqdscVn8R4dNMUd1VoOjZ6AKmLw201VaUhFtlX+u0pjzI6szX7A=="],
@ -735,6 +733,8 @@
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
"autoprefixer": ["autoprefixer@10.4.21", "", { "dependencies": { "browserslist": "^4.24.4", "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ=="],
"axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="],
"b4a": ["b4a@1.6.7", "", {}, "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg=="],
@ -795,6 +795,8 @@
"camelcase": ["camelcase@8.0.0", "", {}, "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA=="],
"camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="],
"caniuse-lite": ["caniuse-lite@1.0.30001721", "", {}, "sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ=="],
"ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
@ -809,7 +811,7 @@
"check-error": ["check-error@2.1.1", "", {}, "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw=="],
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
@ -837,7 +839,7 @@
"comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
"commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],
"commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
"common-path-prefix": ["common-path-prefix@3.0.0", "", {}, "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w=="],
@ -947,8 +949,12 @@
"devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="],
"didyoumean": ["didyoumean@1.2.2", "", {}, "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="],
"diff": ["diff@5.2.0", "", {}, "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A=="],
"dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="],
"dot-prop": ["dot-prop@9.0.0", "", { "dependencies": { "type-fest": "^4.18.2" } }, "sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ=="],
"dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
@ -1087,6 +1093,8 @@
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
"fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="],
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
@ -1119,7 +1127,7 @@
"glob": ["glob@8.1.0", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^5.0.1", "once": "^1.3.0" } }, "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ=="],
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
"glob-regex": ["glob-regex@0.3.2", "", {}, "sha512-m5blUd3/OqDTWwzBBtWBPrGlAzatRywHameHeekAZyZrskYouOGdNB8T/q6JucucvJXtOuyHIn0/Yia7iDasDw=="],
@ -1261,7 +1269,7 @@
"jake": ["jake@10.9.4", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="],
"jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
"jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="],
"js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="],
@ -1311,6 +1319,8 @@
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="],
"lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="],
"limiter": ["limiter@3.0.0", "", {}, "sha512-hev7DuXojsTFl2YwyzUJMDnZ/qBDd3yZQLSH3aD4tdL1cqfc3TMnoecEJtWFaQFdErZsKoFMBTxF/FBSkgDbEg=="],
"lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
@ -1447,12 +1457,16 @@
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
"normalize-range": ["normalize-range@0.1.2", "", {}, "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="],
"npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="],
"nypm": ["nypm@0.6.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "pathe": "^2.0.3", "pkg-types": "^2.0.0", "tinyexec": "^0.3.2" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-mn8wBFV9G9+UFHIrq+pZ2r2zL4aPau/by3kJb3cM7+5tQHMt6HGQB8FDIeKFYp8o0D2pnH6nVsO88N4AmUxIWg=="],
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
"object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="],
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
"object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="],
@ -1525,6 +1539,8 @@
"picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="],
"pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="],
"pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="],
"pkg-types": ["pkg-types@2.1.0", "", { "dependencies": { "confbox": "^0.2.1", "exsolve": "^1.0.1", "pathe": "^2.0.3" } }, "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A=="],
@ -1533,6 +1549,14 @@
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
"postcss-import": ["postcss-import@15.1.0", "", { "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" }, "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew=="],
"postcss-js": ["postcss-js@4.0.1", "", { "dependencies": { "camelcase-css": "^2.0.1" }, "peerDependencies": { "postcss": "^8.4.21" } }, "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw=="],
"postcss-load-config": ["postcss-load-config@4.0.2", "", { "dependencies": { "lilconfig": "^3.0.0", "yaml": "^2.3.4" }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" }, "optionalPeers": ["postcss", "ts-node"] }, "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ=="],
"postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="],
"postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
"postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="],
@ -1583,6 +1607,8 @@
"rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="],
"read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="],
"read-package-up": ["read-package-up@11.0.0", "", { "dependencies": { "find-up-simple": "^1.0.0", "read-pkg": "^9.0.0", "type-fest": "^4.6.0" } }, "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ=="],
"read-pkg": ["read-pkg@9.0.1", "", { "dependencies": { "@types/normalize-package-data": "^2.4.3", "normalize-package-data": "^6.0.0", "parse-json": "^8.0.0", "type-fest": "^4.6.0", "unicorn-magic": "^0.1.0" } }, "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA=="],
@ -1591,7 +1617,7 @@
"readdir-glob": ["readdir-glob@1.1.3", "", { "dependencies": { "minimatch": "^5.1.0" } }, "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA=="],
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
"recast": ["recast@0.23.11", "", { "dependencies": { "ast-types": "^0.16.1", "esprima": "~4.0.0", "source-map": "~0.6.1", "tiny-invariant": "^1.3.3", "tslib": "^2.0.1" } }, "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA=="],
@ -1765,7 +1791,7 @@
"tailwind-variants": ["tailwind-variants@1.0.0", "", { "dependencies": { "tailwind-merge": "3.0.2" }, "peerDependencies": { "tailwindcss": "*" } }, "sha512-2WSbv4ulEEyuBKomOunut65D8UZwxrHoRfYnxGcQNnHqlSCp2+B7Yz2W+yrNDrxRodOXtGD/1oCcKGNBnUqMqA=="],
"tailwindcss": ["tailwindcss@4.1.11", "", {}, "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA=="],
"tailwindcss": ["tailwindcss@3.4.17", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.6", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.2", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og=="],
"tapable": ["tapable@2.2.2", "", {}, "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg=="],
@ -1951,6 +1977,8 @@
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
"yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="],
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
"yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="],
@ -2001,6 +2029,8 @@
"@koshnic/ratelimit/chai": ["chai@4.5.0", "", { "dependencies": { "assertion-error": "^1.1.0", "check-error": "^1.0.3", "deep-eql": "^4.1.3", "get-func-name": "^2.0.2", "loupe": "^2.3.6", "pathval": "^1.1.1", "type-detect": "^4.1.0" } }, "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw=="],
"@netlify/dev-utils/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"@netlify/dev-utils/find-up": ["find-up@7.0.0", "", { "dependencies": { "locate-path": "^7.2.0", "path-exists": "^5.0.0", "unicorn-magic": "^0.1.0" } }, "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g=="],
"@netlify/dev-utils/uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="],
@ -2031,6 +2061,10 @@
"@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"@tailwindcss/node/jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
"@tailwindcss/node/tailwindcss": ["tailwindcss@4.1.11", "", {}, "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
@ -2043,6 +2077,8 @@
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"@tailwindcss/postcss/tailwindcss": ["tailwindcss@4.1.11", "", {}, "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA=="],
"@tanstack/directive-functions-plugin/@babel/code-frame": ["@babel/code-frame@7.26.2", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ=="],
"@tanstack/router-utils/diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="],
@ -2055,8 +2091,6 @@
"@vercel/nft/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
"@vinxi/listhen/jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="],
"@vinxi/listhen/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
"@vue/compiler-core/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
@ -2081,10 +2115,16 @@
"boxen/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
"c12/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"c12/dotenv": ["dotenv@16.5.0", "", {}, "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg=="],
"c12/jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
"c12/magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="],
"chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
"colorspace/color": ["color@3.2.1", "", { "dependencies": { "color-convert": "^1.9.3", "color-string": "^1.6.0" } }, "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA=="],
@ -2109,6 +2149,8 @@
"extract-zip/get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="],
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
"form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
@ -2127,6 +2169,8 @@
"listhen/@parcel/watcher-wasm": ["@parcel/watcher-wasm@2.5.1", "", { "dependencies": { "is-glob": "^4.0.3", "micromatch": "^4.0.5", "napi-wasm": "^1.1.0" } }, "sha512-RJxlQQLkaMMIuWRozy+z2vEqbaQlCuaCgVZIUCzQLYggY22LZbP5Y1+ia+FD724Ids9e+XIyOLXLrLgQSHIthw=="],
"listhen/jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
"listhen/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
"log-symbols/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
@ -2135,18 +2179,20 @@
"mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
"mocha/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
"mocha/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
"mocha/yargs": ["yargs@16.2.0", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw=="],
"netlify/node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="],
"nitropack/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"nitropack/cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="],
"nitropack/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
"nitropack/jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
"nitropack/magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="],
"nitropack/unenv": ["unenv@2.0.0-rc.17", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.4", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-B06u0wXkEd+o5gOCMl/ZHl5cfpYbDZKAT+HWTL+Hws6jWu7dCiqBBXXXzMFcFVJb8D4ytAnYmxJA83uwOQRSsg=="],
@ -2159,6 +2205,8 @@
"parse-json/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
"postcss-nested/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
"precinct/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="],
"read-package-up/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
@ -2169,6 +2217,8 @@
"readdir-glob/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"recrawl-sync/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="],
@ -2179,10 +2229,12 @@
"source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
"sucrase/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
"tailwindcss/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
"terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],
"unenv/mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
"unenv/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
@ -2191,14 +2243,20 @@
"unixify/normalize-path": ["normalize-path@2.1.1", "", { "dependencies": { "remove-trailing-separator": "^1.0.1" } }, "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w=="],
"unstorage/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"untun/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
"untyped/jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
"unwasm/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
"unwasm/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
"unwasm/unplugin": ["unplugin@1.16.1", "", { "dependencies": { "acorn": "^8.14.0", "webpack-virtual-modules": "^0.6.2" } }, "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w=="],
"vinxi/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"vinxi/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
"vinxi/serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="],
@ -2287,6 +2345,8 @@
"@koshnic/ratelimit/chai/pathval": ["pathval@1.1.1", "", {}, "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ=="],
"@netlify/dev-utils/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"@netlify/dev-utils/find-up/locate-path": ["locate-path@7.2.0", "", { "dependencies": { "p-locate": "^6.0.0" } }, "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA=="],
"@netlify/dev-utils/find-up/path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="],
@ -2311,6 +2371,8 @@
"boxen/string-width/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
"c12/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"colorspace/color/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
"concurrently/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
@ -2329,16 +2391,20 @@
"mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
"mocha/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
"mocha/yargs/cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="],
"nitropack/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"sucrase/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"unstorage/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"unwasm/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
"unwasm/pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"vinxi/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"vinxi/serve-static/send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="],
"widest-line/string-width/emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
@ -2357,8 +2423,6 @@
"colorspace/color/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
"mocha/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"mocha/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
"vinxi/serve-static/send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],

View File

@ -1,12 +1,11 @@
"use server";
import { defineConfig } from "@solidjs/start/config";
import tailwindcss from "@tailwindcss/vite";
import tsconfigPaths from "vite-tsconfig-paths";
export default defineConfig({
vite: {
plugins: [tailwindcss(), tsconfigPaths()],
plugins: [tsconfigPaths()],
optimizeDeps: {
include: ["@m3-components/solid"],
esbuildOptions: {
@ -15,5 +14,5 @@ export default defineConfig({
jsxImportSource: "solid-js/h"
}
}
},
}
});

View File

@ -1,10 +1,10 @@
import { defineConfig } from 'drizzle-kit';
import { defineConfig } from "drizzle-kit";
export default defineConfig({
out: './src/drizzle/cred',
schema: './src/db/schema.ts',
dialect: 'postgresql',
out: "./src/drizzle/cred",
schema: "./src/db/schema.ts",
dialect: "postgresql",
dbCredentials: {
url: process.env.DATABASE_URL_CRED!,
},
url: process.env.DATABASE_URL_CRED!
}
});

View File

@ -1,10 +1,10 @@
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';
import "dotenv/config";
import { defineConfig } from "drizzle-kit";
export default defineConfig({
out: './src/drizzle/main',
dialect: 'postgresql',
out: "./src/drizzle/main",
dialect: "postgresql",
dbCredentials: {
url: process.env.DATABASE_URL_MAIN!,
},
url: process.env.DATABASE_URL_MAIN!
}
});

View File

@ -4,15 +4,15 @@
"dev": "vinxi dev --port 7400 --host",
"build": "vinxi build",
"start": "bunx node-env-run --exec bun -- run vinxi start --port 7400",
"version": "vinxi version"
"version": "vinxi version",
"format": "prettier . --write"
},
"dependencies": {
"@m3-components/solid": "0.2.2",
"@m3-components/solid": "0.2.6",
"@solid-primitives/media": "^2.3.3",
"@solidjs/meta": "^0.29.4",
"@solidjs/router": "^0.15.3",
"@solidjs/start": "^1.1.7",
"@tailwindcss/vite": "^4.1.11",
"@types/luxon": "^3.7.1",
"@ungap/has-own": "^0.1.1",
"animejs": "^4.1.2",
@ -24,7 +24,7 @@
"postgres": "^3.4.7",
"solid-js": "^1.9.8",
"tailwind-variants": "^1.0.0",
"tailwindcss": "^4.1.11",
"tailwindcss": "3",
"vinxi": "^0.5.8"
},
"engines": {
@ -35,6 +35,7 @@
"@csstools/postcss-cascade-layers": "^5.0.2",
"@csstools/postcss-oklab-function": "^4.0.10",
"@tailwindcss/postcss": "^4.1.11",
"autoprefixer": "^10.4.21",
"drizzle-kit": "^0.31.4",
"postcss": "^8.5.6",
"tsx": "^4.20.3",

View File

@ -1,9 +0,0 @@
export default {
plugins: {
"@tailwindcss/postcss": {},
// "@csstools/postcss-oklab-function": {},
// "@csstools/postcss-bundler": {},
// "@csstools/postcss-cascade-layers": {},
// "./src/misc/postcss-calc-keyword-polyfill": {}
}
};

View File

@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
};

View File

@ -1,6 +1,48 @@
@import url("https://assets.projectcvsa.com/hm-sans/index.css");
/* @import url("https://assets.projectcvsa.com/hm-sans/index.css"); */
@import "tailwindcss";
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--md-sys-color-background: #fff8f6;
--md-sys-color-on-background: #2a1613;
--md-sys-color-surface: #fff8f6;
--md-sys-color-surface-dim: #f7d2cc;
--md-sys-color-surface-bright: #fff8f6;
--md-sys-color-surface-container-lowest: #ffffff;
--md-sys-color-surface-container-low: #fff0ee;
--md-sys-color-surface-container: #ffe9e6;
--md-sys-color-surface-container-high: #ffe2dd;
--md-sys-color-surface-container-highest: #ffdad4;
--md-sys-color-on-surface: #2a1613;
--md-sys-color-surface-variant: #ffdad4;
--md-sys-color-on-surface-variant: #5f3e39;
--md-sys-color-inverse-surface: #422b27;
--md-sys-color-inverse-on-surface: #ffedea;
--md-sys-color-outline: #946e68;
--md-sys-color-outline-variant: #eabcb4;
--md-sys-color-shadow: #000000;
--md-sys-color-scrim: #000000;
--md-sys-color-surface-tint: #c00100;
--md-sys-color-primary: #ee0000;
--md-sys-color-on-primary: #ffffff;
--md-sys-color-primary-container: #ee0000;
--md-sys-color-on-primary-container: #ffffff;
--md-sys-color-inverse-primary: #ffb4a8;
--md-sys-color-secondary: #b4271a;
--md-sys-color-on-secondary: #ffffff;
--md-sys-color-secondary-container: #ff7460;
--md-sys-color-on-secondary-container: #2f0000;
--md-sys-color-tertiary: #6f4800;
--md-sys-color-on-tertiary: #ffffff;
--md-sys-color-tertiary-container: #9f6900;
--md-sys-color-on-tertiary-container: #ffffff;
--md-sys-color-error: #ba1a1a;
--md-sys-color-on-error: #ffffff;
--md-sys-color-error-container: #ffdad6;
--md-sys-color-on-error-container: #410002;
}
@media (prefers-color-scheme: light) {
:root {
@ -86,44 +128,93 @@
}
}
@theme {
--color-background: var(--md-sys-color-background);
--color-on-background: var(--md-sys-color-on-background);
--color-surface: var(--md-sys-color-surface);
--color-surface-dim: var(--md-sys-color-surface-dim);
--color-surface-bright: var(--md-sys-color-surface-bright);
--color-surface-container-lowest: var(--md-sys-color-surface-container-lowest);
--color-surface-container-low: var(--md-sys-color-surface-container-low);
--color-surface-container: var(--md-sys-color-surface-container);
--color-surface-container-high: var(--md-sys-color-surface-container-high);
--color-surface-container-highest: var(--md-sys-color-surface-container-highest);
--color-on-surface: var(--md-sys-color-on-surface);
--color-surface-variant: var(--md-sys-color-surface-variant);
--color-on-surface-variant: var(--md-sys-color-on-surface-variant);
--color-inverse-surface: var(--md-sys-color-inverse-surface);
--color-inverse-on-surface: var(--md-sys-color-inverse-on-surface);
--color-outline: var(--md-sys-color-outline);
--color-outline-variant: var(--md-sys-color-outline-variant);
--color-shadow: var(--md-sys-color-shadow);
--color-scrim: var(--md-sys-color-scrim);
--color-surface-tint: var(--md-sys-color-surface-tint);
--color-primary: var(--md-sys-color-primary);
--color-on-primary: var(--md-sys-color-on-primary);
--color-primary-container: var(--md-sys-color-primary-container);
--color-on-primary-container: var(--md-sys-color-on-primary-container);
--color-inverse-primary: var(--md-sys-color-inverse-primary);
--color-secondary: var(--md-sys-color-secondary);
--color-on-secondary: var(--md-sys-color-on-secondary);
--color-secondary-container: var(--md-sys-color-secondary-container);
--color-on-secondary-container: var(--md-sys-color-on-secondary-container);
--color-tertiary: var(--md-sys-color-tertiary);
--color-on-tertiary: var(--md-sys-color-on-tertiary);
--color-tertiary-container: var(--md-sys-color-tertiary-container);
--color-on-tertiary-container: var(--md-sys-color-on-tertiary-container);
--color-error: var(--md-sys-color-error);
--color-on-error: var(--md-sys-color-on-error);
--color-error-container: var(--md-sys-color-error-container);
--color-on-error-container: var(--md-sys-color-on-error-container);
.gradient-blur {
inset: auto 0 0 0;
pointer-events: none;
}
.gradient-blur > div,
.gradient-blur::before,
.gradient-blur::after {
position: absolute;
inset: 0;
}
.gradient-blur::before {
content: "";
z-index: 1;
backdrop-filter: blur(0.5px);
mask: linear-gradient(
to bottom,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 1) 12.5%,
rgba(0, 0, 0, 1) 25%,
rgba(0, 0, 0, 0) 37.5%
);
}
.gradient-blur > div:nth-of-type(1) {
z-index: 2;
backdrop-filter: blur(1px);
mask: linear-gradient(
to bottom,
rgba(0, 0, 0, 0) 12.5%,
rgba(0, 0, 0, 1) 25%,
rgba(0, 0, 0, 1) 37.5%,
rgba(0, 0, 0, 0) 50%
);
}
.gradient-blur > div:nth-of-type(2) {
z-index: 3;
backdrop-filter: blur(2px);
mask: linear-gradient(
to bottom,
rgba(0, 0, 0, 0) 25%,
rgba(0, 0, 0, 1) 37.5%,
rgba(0, 0, 0, 1) 50%,
rgba(0, 0, 0, 0) 62.5%
);
}
.gradient-blur > div:nth-of-type(3) {
z-index: 4;
backdrop-filter: blur(4px);
mask: linear-gradient(
to bottom,
rgba(0, 0, 0, 0) 37.5%,
rgba(0, 0, 0, 1) 50%,
rgba(0, 0, 0, 1) 62.5%,
rgba(0, 0, 0, 0) 75%
);
}
.gradient-blur > div:nth-of-type(4) {
z-index: 5;
backdrop-filter: blur(8px);
mask: linear-gradient(
to bottom,
rgba(0, 0, 0, 0) 50%,
rgba(0, 0, 0, 1) 62.5%,
rgba(0, 0, 0, 1) 75%,
rgba(0, 0, 0, 0) 87.5%
);
}
.gradient-blur > div:nth-of-type(5) {
z-index: 6;
backdrop-filter: blur(13px);
mask: linear-gradient(
to bottom,
rgba(0, 0, 0, 0) 62.5%,
rgba(0, 0, 0, 1) 75%,
rgba(0, 0, 0, 1) 87.5%,
rgba(0, 0, 0, 0) 100%
);
}
.gradient-blur > div:nth-of-type(6) {
z-index: 7;
backdrop-filter: blur(24px);
mask: linear-gradient(to bottom, rgba(0, 0, 0, 0) 75%, rgba(0, 0, 0, 1) 87.5%, rgba(0, 0, 0, 1) 100%);
}
.gradient-blur::after {
content: "";
z-index: 8;
backdrop-filter: blur(48px);
mask: linear-gradient(to bottom, rgba(0, 0, 0, 0) 87.5%, rgba(0, 0, 0, 1) 100%);
}
a:not(.clear) {
@ -135,6 +226,13 @@ a:not(.clear) {
@apply bg-surface text-on-surface;
}
@font-face {
font-family: "IPSD";
src: url("/fonts/IBMPlexSansCondDigits-Medium.woff2") format("woff2");
font-weight: 500;
font-style: normal;
}
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;

View File

@ -0,0 +1,12 @@
import { SVGIconComponent } from "~/components/icons/types";
export const RightArrow: SVGIconComponent = (props) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 28 28" {...props}>
<path
fill="currentColor"
d="M18.84 15.17h-13c-.34 0-.61-.12-.84-.34-.22-.22-.33-.5-.33-.83a1.13 1.13 0 0 1 1.17-1.17h13l-3.32-3.32c-.24-.23-.35-.5-.34-.82.01-.3.12-.58.34-.81.23-.24.5-.36.83-.37.32 0 .6.1.83.34l5.34 5.33c.11.12.2.25.25.38a1.34 1.34 0 0 1 0 .88 1 1 0 0 1-.25.38l-5.34 5.33c-.23.24-.51.35-.83.34a1.19 1.19 0 0 1-1.17-1.18c0-.31.1-.58.34-.82l3.32-3.32Z"
/>
</svg>
);
};

View File

@ -0,0 +1,12 @@
import { SVGIconComponent } from "./types";
export const HistoryIcon: SVGIconComponent = (props) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" {...props}>
<path
fill="currentColor"
d="M12 21q-3.15 0-5.575-1.912T3.275 14.2q-.1-.375.15-.687t.675-.363q.4-.05.725.15t.45.6q.6 2.25 2.475 3.675T12 19q2.925 0 4.963-2.037T19 12t-2.037-4.962T12 5q-1.725 0-3.225.8T6.25 8H8q.425 0 .713.288T9 9t-.288.713T8 10H4q-.425 0-.712-.288T3 9V5q0-.425.288-.712T4 4t.713.288T5 5v1.35q1.275-1.6 3.113-2.475T12 3q1.875 0 3.513.713t2.85 1.924t1.925 2.85T21 12t-.712 3.513t-1.925 2.85t-2.85 1.925T12 21m1-9.4l2.5 2.5q.275.275.275.7t-.275.7t-.7.275t-.7-.275l-2.8-2.8q-.15-.15-.225-.337T11 11.975V8q0-.425.288-.712T12 7t.713.288T13 8z"
/>
</svg>
);
};

View File

@ -0,0 +1,12 @@
import { SVGIconComponent } from "./types";
export const LinkIcon: SVGIconComponent = (props) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" {...props}>
<path
fill="currentColor"
d="M11 17H7a4.82 4.82 0 0 1-3.54-1.46A4.82 4.82 0 0 1 2 12c0-1.38.49-2.56 1.46-3.54A4.82 4.82 0 0 1 7 7h4v2H7c-.83 0-1.54.3-2.13.88A2.9 2.9 0 0 0 4 12c0 .83.3 1.54.88 2.13.58.58 1.29.87 2.12.87h4v2Zm-3-4v-2h8v2H8Zm5 4v-2h4c.83 0 1.54-.3 2.13-.88.58-.58.87-1.29.87-2.12 0-.83-.3-1.54-.88-2.13A2.9 2.9 0 0 0 17 9h-4V7h4c1.38 0 2.56.49 3.54 1.46A4.82 4.82 0 0 1 22 12c0 1.38-.49 2.56-1.46 3.54A4.8 4.8 0 0 1 17 17h-4Z"
/>
</svg>
);
};

View File

@ -2,10 +2,10 @@ import { SVGIconComponent } from "./types";
export const MusicIcon: SVGIconComponent = (props) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" {...props}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
<path
d="M13.82 13.82q.58-.58.58-1.42V8H16q.35 0 .57-.23a.8.8 0 0 0 .23-.57.8.8 0 0 0-.23-.57.8.8 0 0 0-.57-.23h-1.6a.8.8 0 0 0-.57.23.8.8 0 0 0-.23.57v3.6a2 2 0 0 0-1.2-.4q-.84 0-1.42.58t-.58 1.42.58 1.42 1.42.58 1.42-.58M8.8 16.8q-.66 0-1.13-.47a1.5 1.5 0 0 1-.47-1.13V5.6q0-.66.47-1.13T8.8 4h9.6q.66 0 1.13.47T20 5.6v9.6q0 .66-.47 1.13t-1.13.47zm0-1.6h9.6V5.6H8.8zM5.6 20q-.66 0-1.13-.47A1.5 1.5 0 0 1 4 18.4V8q0-.34.23-.57a.8.8 0 0 1 .57-.23q.35 0 .57.23.23.22.23.57v10.4H16q.34 0 .57.23.23.22.23.57a.8.8 0 0 1-.8.8zM8.8 5.6v9.6z"
fill="currentColor"
d="M12.5 15q1.05 0 1.775-.725T15 12.5V7h2q.425 0 .713-.288T18 6t-.288-.712T17 5h-2q-.425 0-.712.288T14 6v4.5q-.325-.25-.7-.375T12.5 10q-1.05 0-1.775.725T10 12.5t.725 1.775T12.5 15M8 18q-.825 0-1.412-.587T6 16V4q0-.825.588-1.412T8 2h12q.825 0 1.413.588T22 4v12q0 .825-.587 1.413T20 18zm0-2h12V4H8zm-4 6q-.825 0-1.412-.587T2 20V7q0-.425.288-.712T3 6t.713.288T4 7v13h13q.425 0 .713.288T18 21t-.288.713T17 22zM8 4v12z"
/>
</svg>
);

View File

@ -3,8 +3,10 @@ import { SVGIconComponent } from "~/components/icons/types";
export const SearchIcon: SVGIconComponent = (props) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" {...props}>
<path fill="currentColor"
d="m19.6 21l-6.3-6.3q-.75.6-1.725.95T9.5 16q-2.725 0-4.612-1.888T3 9.5t1.888-4.612T9.5 3t4.613 1.888T16 9.5q0 1.1-.35 2.075T14.7 13.3l6.3 6.3zM9.5 14q1.875 0 3.188-1.312T14 9.5t-1.312-3.187T9.5 5T6.313 6.313T5 9.5t1.313 3.188T9.5 14" />
<path
fill="currentColor"
d="m19.6 21l-6.3-6.3q-.75.6-1.725.95T9.5 16q-2.725 0-4.612-1.888T3 9.5t1.888-4.612T9.5 3t4.613 1.888T16 9.5q0 1.1-.35 2.075T14.7 13.3l6.3 6.3zM9.5 14q1.875 0 3.188-1.312T14 9.5t-1.312-3.187T9.5 5T6.313 6.313T5 9.5t1.313 3.188T9.5 14"
/>
</svg>
);
};
};

View File

@ -0,0 +1,34 @@
import { SVGIconComponent } from "./types";
export const StarBadge4: SVGIconComponent = (props) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" {...props}>
<path
fill="currentColor"
d="M17.78 4c.78 0 1.05.08 1.34.23.28.15.5.37.65.65.15.29.23.56.23 1.34v11.56c0 .78-.08 1.05-.23 1.34-.15.28-.37.5-.65.65-.29.15-.56.23-1.34.23H6.22c-.78 0-1.05-.08-1.34-.23-.28-.15-.5-.37-.65-.65-.15-.29-.23-.56-.23-1.34V6.22c0-.78.08-1.05.23-1.34.15-.28.37-.5.65-.65.29-.15.56-.23 1.34-.23h11.56ZM12 8a.45.45 0 0 0-.45.31l-.78 1.84a.43.43 0 0 1-.36.26l-1.97.16c-.24.02-.39.13-.46.34a.5.5 0 0 0 .15.54l1.52 1.31c.12.1.17.26.13.42l-.44 1.93c-.05.22.01.4.19.52.17.12.35.13.54 0l1.71-1.01a.4.4 0 0 1 .44 0l1.71 1.02c.19.12.37.11.54-.01.18-.13.24-.3.19-.52l-.44-1.93a.43.43 0 0 1 .13-.42l1.52-1.31a.48.48 0 0 0 .15-.54c-.07-.21-.22-.32-.46-.34l-1.97-.16a.43.43 0 0 1-.36-.26l-.78-1.84a.45.45 0 0 0-.45-.3Z"
/>
</svg>
);
};
export const StarBadge6: SVGIconComponent = (props) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" {...props}>
<path
fill="currentColor"
d="M12.52 2.64c.17.1.3.23.4.4l1.97 3.42h4.54c.18 0 .36.05.52.14h.01c.52.3.7.96.4 1.47L18.09 12l2.25 3.9a1.07 1.07 0 0 1-.93 1.6h-4.5l-1.97 3.43c-.1.16-.22.3-.38.39h-.01c-.52.3-1.17.13-1.47-.39l-1.97-3.42H4.57a1.07 1.07 0 0 1-.93-1.61l2.27-3.93-2.25-3.9a1.07 1.07 0 0 1-.14-.52v-.01c0-.6.48-1.08 1.07-1.08h4.5l1.97-3.42c.3-.52.95-.7 1.46-.4ZM12 8.61a.4.4 0 0 0-.39.25l-.67 1.6a.43.43 0 0 1-.36.26l-1.7.13c-.2.01-.34.11-.4.3a.42.42 0 0 0 .14.47l1.3 1.13c.12.1.17.26.13.42l-.38 1.66c-.04.19.01.34.17.45.15.11.3.11.47.01l1.47-.88c.14-.08.3-.08.44 0l1.47.88c.17.1.32.1.48 0a.4.4 0 0 0 .16-.45l-.38-1.67a.43.43 0 0 1 .14-.42l1.3-1.13c.14-.13.19-.29.13-.47s-.19-.28-.39-.3l-1.7-.13a.43.43 0 0 1-.36-.26l-.67-1.59a.4.4 0 0 0-.4-.26Z"
/>
</svg>
);
};
export const StarBadge8: SVGIconComponent = (props) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" {...props}>
<path
fill="currentColor"
d="m12.22 14.25 1.43.86c.16.1.31.1.46-.01a.4.4 0 0 0 .16-.44l-.37-1.62a.42.42 0 0 1 .14-.41l1.26-1.1a.4.4 0 0 0 .13-.46c-.06-.18-.19-.28-.39-.3l-1.65-.12a.42.42 0 0 1-.35-.26l-.65-1.54a.39.39 0 0 0-.39-.26.39.39 0 0 0-.39.26l-.65 1.54a.42.42 0 0 1-.35.26l-1.65.13c-.2.01-.33.1-.39.29a.4.4 0 0 0 .13.46l1.26 1.1c.12.1.18.26.14.41l-.37 1.62c-.04.18 0 .33.16.44.15.1.3.1.46 0l1.43-.85c.14-.08.3-.08.44 0Zm-3.27 4.6h-2.1c-.46 0-.87-.16-1.2-.5-.34-.33-.5-.74-.5-1.2v-2.1a.42.42 0 0 0-.13-.3L3.5 13.2a1.93 1.93 0 0 1-.36-.57 1.64 1.64 0 0 1 0-1.26c.08-.2.2-.4.36-.57l1.53-1.55a.42.42 0 0 0 .12-.3v-2.1c0-.46.17-.87.5-1.2.34-.34.75-.5 1.22-.5h2.1c.1 0 .21-.05.3-.13L10.8 3.5c.17-.15.36-.28.57-.36a1.64 1.64 0 0 1 1.26 0c.21.08.4.2.57.36l1.55 1.53a.4.4 0 0 0 .3.12h2.1c.46 0 .87.17 1.2.5.34.34.5.75.5 1.22v2.1c0 .1.05.21.13.3l1.53 1.54c.15.17.28.36.36.57a1.64 1.64 0 0 1 0 1.26c-.08.21-.2.4-.36.57l-1.53 1.55a.42.42 0 0 0-.12.3v2.1c0 .46-.17.87-.5 1.2-.34.34-.75.5-1.22.5h-2.1a.42.42 0 0 0-.3.13L13.2 20.5a1.9 1.9 0 0 1-.57.36 1.64 1.64 0 0 1-1.26 0c-.2-.08-.4-.2-.57-.36l-1.55-1.53a.42.42 0 0 0-.3-.12Z"
/>
</svg>
);
};

View File

@ -2,4 +2,4 @@ export * from "./Home";
export * from "./Music";
export * from "./Album";
export * from "./Search";
export * from "./Edit";
export * from "./Edit";

View File

@ -1,3 +1,3 @@
import { Component, JSX } from "solid-js";
type SVGIconComponent = Component<JSX.SvgSVGAttributes<SVGSVGElement>>;
type SVGIconComponent = Component<JSX.SvgSVGAttributes<SVGSVGElement>>;

View File

@ -3,7 +3,7 @@ import { DivProps } from "~/components/common";
export const BodyRegion: Component<DivProps> = (props) => {
return (
<div class="min-h-full" {...props}>
<div class="w-full min-h-full" {...props}>
{props.children}
</div>
);

View File

@ -12,8 +12,8 @@ import {
export const NavigationDesktop: Component = () => {
return (
<AppBar class="hidden lg:flex h-20 xl:h-22 2xl:h-24" variant="search">
<AppBarLeadingElement class="h-full grow shrink basis-0">
<AppBar class="hidden lg:flex h-20 xl:h-22 2xl:h-24 z-20" variant="search">
<AppBarLeadingElement class="ml-4 h-full grow shrink basis-0">
<DynamicImage
class="lg:block h-full"
darkSrc="/icons/zh/appbar_desktop_dark.svg"
@ -21,7 +21,11 @@ export const NavigationDesktop: Component = () => {
/>
</AppBarLeadingElement>
<AppBarSearchContainer>
<AppBarSearchBox class="mx-auto text-center" placeholder="搜索" />
<AppBarSearchBox
class="mx-auto text-center placeholder-on-surface-variant text-on-surface
placeholder:font-light"
placeholder="搜索"
/>
</AppBarSearchContainer>
<AppBarTrailingElementGroup class="h-full grow shrink basis-0">
<AppBarTrailingElement>

View File

@ -11,7 +11,8 @@ import {
AppBarTrailingElementGroup,
AppBarTrailingElement,
IconButton,
AppBarSearchContainer
AppBarSearchContainer,
ExtendedFAB
} from "@m3-components/solid";
import { A } from "@solidjs/router";
import { SearchIcon } from "~/components/icons/Search";
@ -33,7 +34,7 @@ export const NavigationMobile: Component<{ lang?: "zh" | "en" }> = (props) => {
});
} else {
animate(el()!, {
x: -340,
x: -380,
duration: 500,
z: 0,
ease: "cubicBezier(0.27, 1.06, 0.18, 1.00)"
@ -44,17 +45,17 @@ export const NavigationMobile: Component<{ lang?: "zh" | "en" }> = (props) => {
return (
<>
<NavigationRailMenu
class="top-3 left-4 fixed z-100 bg-surface-container/60 backdrop-blur-md lg:hidden"
class="top-3 left-4 fixed z-[100] backdrop-blur-md shadow-xl lg:hidden"
onClick={() => {
setNavigationExpanded(!navigationExpanded());
}}
/>
<AppBar class="lg:hidden" variant="search">
<AppBar class="z-20 lg:hidden" variant="search">
<AppBarLeadingElement>
<NavigationRailMenu class="invisible" />
</AppBarLeadingElement>
<AppBarSearchContainer class="max-sm:w-[calc(100%-7.9rem)]">
<AppBarSearchBox placeholder="搜索" />
<AppBarSearchBox placeholder="搜索" class="placeholder-on-surface-variant text-on-surface" />
</AppBarSearchContainer>
<AppBarTrailingElementGroup>
<AppBarTrailingElement>
@ -71,13 +72,19 @@ export const NavigationMobile: Component<{ lang?: "zh" | "en" }> = (props) => {
}}
>
<NavigationRail
class="top-0 bg-surface-container rounded-r-2xl shadow-shadow shadow-2xl"
class="z-20 top-0 bg-background overflow-auto rounded-r-2xl shadow-shadow shadow-2xl"
width={256}
expanded={true}
>
<NavigationRailFAB text={searchT[props.lang || "zh"]} class="pr-6 mt-6" color="primary">
<ExtendedFAB
text={searchT[props.lang || "zh"]}
class="left-5 top-5 font-medium leading-6 duration-100 whitespace-nowrap
transition-none w-24 h-14 text-base mt-6"
color="primary"
position="unset"
>
<SearchIcon />
</NavigationRailFAB>
</ExtendedFAB>
<NavigationRailActions>
<For each={props.lang == "en" ? actionsEn : actions}>
{(action, index) => (
@ -96,6 +103,10 @@ export const NavigationMobile: Component<{ lang?: "zh" | "en" }> = (props) => {
</For>
</NavigationRailActions>
</NavigationRail>
<div
onclick={() => setNavigationExpanded(false)}
class="w-screen h-screen z-10 absoluter bg-transparent"
></div>
</div>
</Portal>
</>

View File

@ -1,6 +1,6 @@
import { dbCred } from "~db/index";
import { loginSessions, users } from "~db/cred/schema";
import { and, eq, gt, isNull, sql } from "drizzle-orm";
import { and, eq, gt, isNull, sql } from "drizzle-orm";
import { SensitiveUserFields, UserType } from "~db/outerSchema";
type ReturnedUser = Omit<UserType, SensitiveUserFields>;
@ -45,4 +45,4 @@ export const getUserLoggedin = async (sessionID?: string): Promise<ReturnedUser
console.log("Query for sessionID:", sessionID);
return user[0];
};
};

View File

@ -1,11 +1,11 @@
import { Accessor, Component, createSignal } from "solid-js";
import { createContext, useContext } from 'solid-js';
import { createContext, useContext } from "solid-js";
type Hook = {
memoizedValue: any | null;
deps: any[] | null;
promise: Promise<any> | null;
}
};
export type RequestContextValue = Map<string, Hook>;
@ -17,7 +17,7 @@ export const RequestContextProvider: Component<{ children: any }> = (props) => {
const initValue: RequestContextValue = new Map();
const [value, setValue] = createSignal(initValue);
const updateValue = (v: RequestContextValue) => {
setValue(v)
setValue(v);
};
const context: Context = [value, updateValue];
@ -28,7 +28,7 @@ export const RequestContextProvider: Component<{ children: any }> = (props) => {
export function useRequestContext(): Context {
const ctx = useContext(RequestContext);
if (!ctx) {
throw new Error('useRequestContext must be used within a RequestContextProvider');
throw new Error("useRequestContext must be used within a RequestContextProvider");
}
return ctx;
}
}

View File

@ -8,27 +8,32 @@ export const TabSwitcher: Component<ElementProps> = (props) => {
return (
<nav class="flex flex-col" {...rest}>
<div class="w-full lg:w-48 gap-4 flex lg:flex-col items-center lg:self-center 2xl:self-end">
<A class="w-full" href="../info">
<div class="w-full lg:w-48 gap-4 flex overflow-auto lg:flex-col items-center lg:self-center 2xl:self-end">
<A class="min-w-20 w-full" href="../info">
<Button class="w-full" variant="filled">
</Button>
</A>
<A class="w-full" href="../lyrics">
<A class="min-w-20 w-full" href="../lyrics">
<Button class="w-full" variant="outlined">
</Button>
</A>
<A class="w-full" href="../analytics">
<A class="min-w-20 w-full" href="../analytics">
<Button class="w-full" variant="outlined">
</Button>
</A>
<A class="w-full" href="../relations">
<A class="min-w-20 w-full" href="../relations">
<Button class="w-full" variant="outlined">
</Button>
</A>
<A class="min-w-20 w-full" href="../discussion">
<Button class="w-full" variant="outlined">
</Button>
</A>
</div>
</nav>
);

View File

@ -18,5 +18,5 @@ export const DynamicImage: Component<Props> = (props) => {
<img src={v.lightSrc} alt={v.alt} {...rest} />
</Match>
</Switch>
)
}
);
};

View File

@ -1,350 +1,350 @@
{
"id": "00000000-0000-0000-0000-000000000000",
"prevId": "",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.captcha_difficulty_settings": {
"name": "captcha_difficulty_settings",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": "nextval('captcha_difficulty_settings_id_seq'::regclass)"
},
"method": {
"name": "method",
"type": "text",
"primaryKey": false,
"notNull": true
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": true
},
"duration": {
"name": "duration",
"type": "real",
"primaryKey": false,
"notNull": true
},
"threshold": {
"name": "threshold",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"difficulty": {
"name": "difficulty",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"global": {
"name": "global",
"type": "boolean",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"captcha_difficulty_settings_pkey": {
"name": "captcha_difficulty_settings_pkey",
"columns": [
{
"expression": "id",
"asc": true,
"nulls": "last",
"opclass": "int4_ops",
"isExpression": false
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {},
"policies": {},
"isRLSEnabled": false
},
"public.login_sessions": {
"name": "login_sessions",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"uid": {
"name": "uid",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "CURRENT_TIMESTAMP"
},
"expire_at": {
"name": "expire_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"last_used_at": {
"name": "last_used_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"ip_address": {
"name": "ip_address",
"type": "inet",
"primaryKey": false,
"notNull": false
},
"user_agent": {
"name": "user_agent",
"type": "text",
"primaryKey": false,
"notNull": false
},
"deactivated_at": {
"name": "deactivated_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"inx_login-sessions_uid": {
"name": "inx_login-sessions_uid",
"columns": [
{
"expression": "uid",
"asc": true,
"nulls": "last",
"opclass": "int4_ops",
"isExpression": false
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"login_sessions_pkey": {
"name": "login_sessions_pkey",
"columns": [
{
"expression": "id",
"asc": true,
"nulls": "last",
"opclass": "text_ops",
"isExpression": false
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {},
"policies": {},
"isRLSEnabled": false
},
"public.users": {
"name": "users",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": "nextval('users_id_seq'::regclass)"
},
"nickname": {
"name": "nickname",
"type": "text",
"primaryKey": false,
"notNull": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": true
},
"unq_id": {
"name": "unq_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"role": {
"name": "role",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'USER'"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "CURRENT_TIMESTAMP"
}
},
"indexes": {
"users_pkey": {
"name": "users_pkey",
"columns": [
{
"expression": "id",
"asc": true,
"nulls": "last",
"opclass": "int4_ops",
"isExpression": false
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
},
"users_pkey1": {
"name": "users_pkey1",
"columns": [
{
"expression": "id",
"asc": true,
"nulls": "last",
"opclass": "int4_ops",
"isExpression": false
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
},
"users_unq_id_key": {
"name": "users_unq_id_key",
"columns": [
{
"expression": "unq_id",
"asc": true,
"nulls": "last",
"opclass": "text_ops",
"isExpression": false
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
},
"users_username_key": {
"name": "users_username_key",
"columns": [
{
"expression": "username",
"asc": true,
"nulls": "last",
"opclass": "text_ops",
"isExpression": false
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {},
"policies": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {
"public.captcha_difficulty_settings_id_seq": {
"name": "captcha_difficulty_settings_id_seq",
"schema": "public",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"increment": "1",
"cycle": false,
"cache": "1"
},
"public.users_id_seq": {
"name": "users_id_seq",
"schema": "public",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"increment": "1",
"cycle": false,
"cache": "1"
}
},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {
"captcha_difficulty_settings": {
"columns": {
"id": {
"isDefaultAnExpression": true
}
}
},
"users": {
"columns": {
"id": {
"isDefaultAnExpression": true
}
}
}
}
}
}
"id": "00000000-0000-0000-0000-000000000000",
"prevId": "",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.captcha_difficulty_settings": {
"name": "captcha_difficulty_settings",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": "nextval('captcha_difficulty_settings_id_seq'::regclass)"
},
"method": {
"name": "method",
"type": "text",
"primaryKey": false,
"notNull": true
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": true
},
"duration": {
"name": "duration",
"type": "real",
"primaryKey": false,
"notNull": true
},
"threshold": {
"name": "threshold",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"difficulty": {
"name": "difficulty",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"global": {
"name": "global",
"type": "boolean",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"captcha_difficulty_settings_pkey": {
"name": "captcha_difficulty_settings_pkey",
"columns": [
{
"expression": "id",
"asc": true,
"nulls": "last",
"opclass": "int4_ops",
"isExpression": false
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {},
"policies": {},
"isRLSEnabled": false
},
"public.login_sessions": {
"name": "login_sessions",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"uid": {
"name": "uid",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "CURRENT_TIMESTAMP"
},
"expire_at": {
"name": "expire_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"last_used_at": {
"name": "last_used_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"ip_address": {
"name": "ip_address",
"type": "inet",
"primaryKey": false,
"notNull": false
},
"user_agent": {
"name": "user_agent",
"type": "text",
"primaryKey": false,
"notNull": false
},
"deactivated_at": {
"name": "deactivated_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"inx_login-sessions_uid": {
"name": "inx_login-sessions_uid",
"columns": [
{
"expression": "uid",
"asc": true,
"nulls": "last",
"opclass": "int4_ops",
"isExpression": false
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"login_sessions_pkey": {
"name": "login_sessions_pkey",
"columns": [
{
"expression": "id",
"asc": true,
"nulls": "last",
"opclass": "text_ops",
"isExpression": false
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {},
"policies": {},
"isRLSEnabled": false
},
"public.users": {
"name": "users",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": "nextval('users_id_seq'::regclass)"
},
"nickname": {
"name": "nickname",
"type": "text",
"primaryKey": false,
"notNull": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": true
},
"unq_id": {
"name": "unq_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"role": {
"name": "role",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'USER'"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "CURRENT_TIMESTAMP"
}
},
"indexes": {
"users_pkey": {
"name": "users_pkey",
"columns": [
{
"expression": "id",
"asc": true,
"nulls": "last",
"opclass": "int4_ops",
"isExpression": false
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
},
"users_pkey1": {
"name": "users_pkey1",
"columns": [
{
"expression": "id",
"asc": true,
"nulls": "last",
"opclass": "int4_ops",
"isExpression": false
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
},
"users_unq_id_key": {
"name": "users_unq_id_key",
"columns": [
{
"expression": "unq_id",
"asc": true,
"nulls": "last",
"opclass": "text_ops",
"isExpression": false
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
},
"users_username_key": {
"name": "users_username_key",
"columns": [
{
"expression": "username",
"asc": true,
"nulls": "last",
"opclass": "text_ops",
"isExpression": false
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {},
"policies": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {
"public.captcha_difficulty_settings_id_seq": {
"name": "captcha_difficulty_settings_id_seq",
"schema": "public",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"increment": "1",
"cycle": false,
"cache": "1"
},
"public.users_id_seq": {
"name": "users_id_seq",
"schema": "public",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"increment": "1",
"cycle": false,
"cache": "1"
}
},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {
"captcha_difficulty_settings": {
"columns": {
"id": {
"isDefaultAnExpression": true
}
}
},
"users": {
"columns": {
"id": {
"isDefaultAnExpression": true
}
}
}
}
}
}

View File

@ -1,13 +1,13 @@
{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1750513073792,
"tag": "0000_moaning_shotgun",
"breakpoints": true
}
]
}
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1750513073792,
"tag": "0000_moaning_shotgun",
"breakpoints": true
}
]
}

View File

@ -1,3 +1,2 @@
import { relations } from "drizzle-orm/relations";
import { } from "./schema";
import {} from "./schema";

View File

@ -1,47 +1,93 @@
import { pgTable, uniqueIndex, integer, text, real, boolean, index, timestamp, inet, pgSequence } from "drizzle-orm/pg-core"
import { sql } from "drizzle-orm"
import {
pgTable,
uniqueIndex,
integer,
text,
real,
boolean,
index,
timestamp,
inet,
pgSequence
} from "drizzle-orm/pg-core";
import { sql } from "drizzle-orm";
export const captchaDifficultySettingsIdSeq = pgSequence("captcha_difficulty_settings_id_seq", {
startWith: "1",
increment: "1",
minValue: "1",
maxValue: "2147483647",
cache: "1",
cycle: false
});
export const usersIdSeq = pgSequence("users_id_seq", {
startWith: "1",
increment: "1",
minValue: "1",
maxValue: "2147483647",
cache: "1",
cycle: false
});
export const captchaDifficultySettingsIdSeq = pgSequence("captcha_difficulty_settings_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "2147483647", cache: "1", cycle: false })
export const usersIdSeq = pgSequence("users_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "2147483647", cache: "1", cycle: false })
export const captchaDifficultySettings = pgTable(
"captcha_difficulty_settings",
{
id: integer()
.default(sql`nextval('captcha_difficulty_settings_id_seq'::regclass)`)
.notNull(),
method: text().notNull(),
path: text().notNull(),
duration: real().notNull(),
threshold: integer().notNull(),
difficulty: integer().notNull(),
global: boolean().notNull()
},
(table) => [
uniqueIndex("captcha_difficulty_settings_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops"))
]
);
export const captchaDifficultySettings = pgTable("captcha_difficulty_settings", {
id: integer().default(sql`nextval('captcha_difficulty_settings_id_seq'::regclass)`).notNull(),
method: text().notNull(),
path: text().notNull(),
duration: real().notNull(),
threshold: integer().notNull(),
difficulty: integer().notNull(),
global: boolean().notNull(),
}, (table) => [
uniqueIndex("captcha_difficulty_settings_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
]);
export const loginSessions = pgTable(
"login_sessions",
{
id: text().notNull(),
uid: integer().notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" })
.default(sql`CURRENT_TIMESTAMP`)
.notNull(),
expireAt: timestamp("expire_at", { withTimezone: true, mode: "string" }),
lastUsedAt: timestamp("last_used_at", { withTimezone: true, mode: "string" }),
ipAddress: inet("ip_address"),
userAgent: text("user_agent"),
deactivatedAt: timestamp("deactivated_at", { withTimezone: true, mode: "string" })
},
(table) => [
index("inx_login-sessions_uid").using("btree", table.uid.asc().nullsLast().op("int4_ops")),
uniqueIndex("login_sessions_pkey").using("btree", table.id.asc().nullsLast().op("text_ops"))
]
);
export const loginSessions = pgTable("login_sessions", {
id: text().notNull(),
uid: integer().notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
expireAt: timestamp("expire_at", { withTimezone: true, mode: 'string' }),
lastUsedAt: timestamp("last_used_at", { withTimezone: true, mode: 'string' }),
ipAddress: inet("ip_address"),
userAgent: text("user_agent"),
deactivatedAt: timestamp("deactivated_at", { withTimezone: true, mode: 'string' }),
}, (table) => [
index("inx_login-sessions_uid").using("btree", table.uid.asc().nullsLast().op("int4_ops")),
uniqueIndex("login_sessions_pkey").using("btree", table.id.asc().nullsLast().op("text_ops")),
]);
export const users = pgTable("users", {
id: integer().default(sql`nextval('users_id_seq'::regclass)`).notNull(),
nickname: text(),
username: text().notNull(),
password: text().notNull(),
unqId: text("unq_id").default(sql`gen_random_uuid()`).notNull(),
role: text().default('USER').notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
}, (table) => [
uniqueIndex("users_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
uniqueIndex("users_pkey1").using("btree", table.id.asc().nullsLast().op("int4_ops")),
uniqueIndex("users_unq_id_key").using("btree", table.unqId.asc().nullsLast().op("text_ops")),
uniqueIndex("users_username_key").using("btree", table.username.asc().nullsLast().op("text_ops")),
]);
export const users = pgTable(
"users",
{
id: integer()
.default(sql`nextval('users_id_seq'::regclass)`)
.notNull(),
nickname: text(),
username: text().notNull(),
password: text().notNull(),
unqId: text("unq_id")
.default(sql`gen_random_uuid()`)
.notNull(),
role: text().default("USER").notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" })
.default(sql`CURRENT_TIMESTAMP`)
.notNull()
},
(table) => [
uniqueIndex("users_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
uniqueIndex("users_pkey1").using("btree", table.id.asc().nullsLast().op("int4_ops")),
uniqueIndex("users_unq_id_key").using("btree", table.unqId.asc().nullsLast().op("text_ops")),
uniqueIndex("users_username_key").using("btree", table.username.asc().nullsLast().op("text_ops"))
]
);

View File

@ -1,7 +1,7 @@
"use server";
import { drizzle } from 'drizzle-orm/postgres-js';
import { drizzle } from "drizzle-orm/postgres-js";
import { sqlCred, sql } from "@cvsa/core";
export const dbMain = drizzle(sql);
export const dbCred = drizzle(sqlCred);
export const dbCred = drizzle(sqlCred);

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1750513105905,
"tag": "0000_fresh_mac_gargan",
"breakpoints": true
}
]
}
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1750513105905,
"tag": "0000_fresh_mac_gargan",
"breakpoints": true
}
]
}

View File

@ -1,3 +1,2 @@
import { relations } from "drizzle-orm/relations";
import { } from "./schema";
import {} from "./schema";

View File

@ -1,178 +1,316 @@
import { pgTable, index, text, timestamp, unique, serial, bigint, integer, uniqueIndex, varchar, uuid, smallint, bigserial, boolean, interval, real, pgSequence } from "drizzle-orm/pg-core"
import { sql } from "drizzle-orm"
import {
pgTable,
index,
text,
timestamp,
unique,
serial,
bigint,
integer,
uniqueIndex,
varchar,
uuid,
smallint,
bigserial,
boolean,
interval,
real,
pgSequence
} from "drizzle-orm/pg-core";
import { sql } from "drizzle-orm";
export const allDataIdSeq = pgSequence("all_data_id_seq", {
startWith: "1",
increment: "1",
minValue: "1",
maxValue: "2147483647",
cache: "1",
cycle: false
});
export const labelingResultIdSeq = pgSequence("labeling_result_id_seq", {
startWith: "1",
increment: "1",
minValue: "1",
maxValue: "2147483647",
cache: "1",
cycle: false
});
export const songsIdSeq = pgSequence("songs_id_seq", {
startWith: "1",
increment: "1",
minValue: "1",
maxValue: "2147483647",
cache: "1",
cycle: false
});
export const videoSnapshotIdSeq = pgSequence("video_snapshot_id_seq", {
startWith: "1",
increment: "1",
minValue: "1",
maxValue: "2147483647",
cache: "1",
cycle: false
});
export const viewsIncrementRateIdSeq = pgSequence("views_increment_rate_id_seq", {
startWith: "1",
increment: "1",
minValue: "1",
maxValue: "9223372036854775807",
cache: "1",
cycle: false
});
export const allDataIdSeq = pgSequence("all_data_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "2147483647", cache: "1", cycle: false })
export const labelingResultIdSeq = pgSequence("labeling_result_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "2147483647", cache: "1", cycle: false })
export const songsIdSeq = pgSequence("songs_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "2147483647", cache: "1", cycle: false })
export const videoSnapshotIdSeq = pgSequence("video_snapshot_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "2147483647", cache: "1", cycle: false })
export const viewsIncrementRateIdSeq = pgSequence("views_increment_rate_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "9223372036854775807", cache: "1", cycle: false })
export const content = pgTable(
"content",
{
pageId: text("page_id").primaryKey().notNull(),
pageContent: text("page_content").notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" })
.default(sql`CURRENT_TIMESTAMP`)
.notNull(),
updatedAt: timestamp("updated_at", { withTimezone: true, mode: "string" }),
deletedAt: timestamp("deleted_at", { withTimezone: true, mode: "string" })
},
(table) => [index("idx_content_created-at").using("btree", table.createdAt.asc().nullsLast().op("timestamptz_ops"))]
);
export const content = pgTable("content", {
pageId: text("page_id").primaryKey().notNull(),
pageContent: text("page_content").notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }),
deletedAt: timestamp("deleted_at", { withTimezone: true, mode: 'string' }),
}, (table) => [
index("idx_content_created-at").using("btree", table.createdAt.asc().nullsLast().op("timestamptz_ops")),
]);
export const bilibiliUser = pgTable(
"bilibili_user",
{
id: serial().primaryKey().notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
uid: bigint({ mode: "number" }).notNull(),
username: text().notNull(),
desc: text().notNull(),
fans: integer().notNull()
},
(table) => [
index("idx_bili-user_uid").using("btree", table.uid.asc().nullsLast().op("int8_ops")),
unique("unq_bili-user_uid").on(table.uid)
]
);
export const bilibiliUser = pgTable("bilibili_user", {
id: serial().primaryKey().notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
uid: bigint({ mode: "number" }).notNull(),
username: text().notNull(),
desc: text().notNull(),
fans: integer().notNull(),
}, (table) => [
index("idx_bili-user_uid").using("btree", table.uid.asc().nullsLast().op("int8_ops")),
unique("unq_bili-user_uid").on(table.uid),
]);
export const bilibiliMetadata = pgTable(
"bilibili_metadata",
{
id: integer()
.default(sql`nextval('all_data_id_seq'::regclass)`)
.notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }).notNull(),
bvid: varchar({ length: 12 }),
description: text(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
uid: bigint({ mode: "number" }),
tags: text(),
title: text(),
publishedAt: timestamp("published_at", { withTimezone: true, mode: "string" }),
duration: integer(),
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" }).default(sql`CURRENT_TIMESTAMP`),
status: integer().default(0).notNull(),
coverUrl: text("cover_url")
},
(table) => [
uniqueIndex("all_data_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
index("idx_all-data_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
index("idx_all-data_bvid").using("btree", table.bvid.asc().nullsLast().op("text_ops")),
index("idx_all-data_uid").using("btree", table.uid.asc().nullsLast().op("int8_ops")),
index("idx_bili-meta_status").using("btree", table.status.asc().nullsLast().op("int4_ops")),
uniqueIndex("unq_all-data_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops"))
]
);
export const bilibiliMetadata = pgTable("bilibili_metadata", {
id: integer().default(sql`nextval('all_data_id_seq'::regclass)`).notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }).notNull(),
bvid: varchar({ length: 12 }),
description: text(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
uid: bigint({ mode: "number" }),
tags: text(),
title: text(),
publishedAt: timestamp("published_at", { withTimezone: true, mode: 'string' }),
duration: integer(),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`),
status: integer().default(0).notNull(),
coverUrl: text("cover_url"),
}, (table) => [
uniqueIndex("all_data_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
index("idx_all-data_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
index("idx_all-data_bvid").using("btree", table.bvid.asc().nullsLast().op("text_ops")),
index("idx_all-data_uid").using("btree", table.uid.asc().nullsLast().op("int8_ops")),
index("idx_bili-meta_status").using("btree", table.status.asc().nullsLast().op("int4_ops")),
uniqueIndex("unq_all-data_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
]);
export const classifiedLabelsHuman = pgTable(
"classified_labels_human",
{
id: serial().primaryKey().notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }).notNull(),
author: uuid().notNull(),
label: smallint().notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" })
.default(sql`CURRENT_TIMESTAMP`)
.notNull()
},
(table) => [
index("idx_classified-labels-human_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
index("idx_classified-labels-human_author").using("btree", table.author.asc().nullsLast().op("uuid_ops")),
index("idx_classified-labels-human_created-at").using(
"btree",
table.createdAt.asc().nullsLast().op("timestamptz_ops")
),
index("idx_classified-labels-human_label").using("btree", table.label.asc().nullsLast().op("int2_ops"))
]
);
export const classifiedLabelsHuman = pgTable("classified_labels_human", {
id: serial().primaryKey().notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }).notNull(),
author: uuid().notNull(),
label: smallint().notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
}, (table) => [
index("idx_classified-labels-human_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
index("idx_classified-labels-human_author").using("btree", table.author.asc().nullsLast().op("uuid_ops")),
index("idx_classified-labels-human_created-at").using("btree", table.createdAt.asc().nullsLast().op("timestamptz_ops")),
index("idx_classified-labels-human_label").using("btree", table.label.asc().nullsLast().op("int2_ops")),
]);
export const labellingResult = pgTable(
"labelling_result",
{
id: integer()
.default(sql`nextval('labeling_result_id_seq'::regclass)`)
.notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }).notNull(),
label: smallint().notNull(),
modelVersion: text("model_version").notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" })
.default(sql`CURRENT_TIMESTAMP`)
.notNull(),
logits: smallint().array()
},
(table) => [
index("idx_labeling_label_model-version").using(
"btree",
table.label.asc().nullsLast().op("int2_ops"),
table.modelVersion.asc().nullsLast().op("int2_ops")
),
index("idx_labeling_model-version").using("btree", table.modelVersion.asc().nullsLast().op("text_ops")),
index("idx_labelling_aid-label").using(
"btree",
table.aid.asc().nullsLast().op("int2_ops"),
table.label.asc().nullsLast().op("int2_ops")
),
uniqueIndex("labeling_result_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
uniqueIndex("unq_labelling-result_aid_model-version").using(
"btree",
table.aid.asc().nullsLast().op("int8_ops"),
table.modelVersion.asc().nullsLast().op("int8_ops")
)
]
);
export const labellingResult = pgTable("labelling_result", {
id: integer().default(sql`nextval('labeling_result_id_seq'::regclass)`).notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }).notNull(),
label: smallint().notNull(),
modelVersion: text("model_version").notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
logits: smallint().array(),
}, (table) => [
index("idx_labeling_label_model-version").using("btree", table.label.asc().nullsLast().op("int2_ops"), table.modelVersion.asc().nullsLast().op("int2_ops")),
index("idx_labeling_model-version").using("btree", table.modelVersion.asc().nullsLast().op("text_ops")),
index("idx_labelling_aid-label").using("btree", table.aid.asc().nullsLast().op("int2_ops"), table.label.asc().nullsLast().op("int2_ops")),
uniqueIndex("labeling_result_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
uniqueIndex("unq_labelling-result_aid_model-version").using("btree", table.aid.asc().nullsLast().op("int8_ops"), table.modelVersion.asc().nullsLast().op("int8_ops")),
]);
export const latestVideoSnapshot = pgTable(
"latest_video_snapshot",
{
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }).primaryKey().notNull(),
time: timestamp({ withTimezone: true, mode: "string" }).notNull(),
views: integer().notNull(),
coins: integer().notNull(),
likes: integer().notNull(),
favorites: integer().notNull(),
replies: integer().notNull(),
danmakus: integer().notNull(),
shares: integer().notNull()
},
(table) => [
index("idx_latest-video-snapshot_time").using("btree", table.time.asc().nullsLast().op("timestamptz_ops")),
index("idx_latest-video-snapshot_views").using("btree", table.views.asc().nullsLast().op("int4_ops"))
]
);
export const latestVideoSnapshot = pgTable("latest_video_snapshot", {
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }).primaryKey().notNull(),
time: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
views: integer().notNull(),
coins: integer().notNull(),
likes: integer().notNull(),
favorites: integer().notNull(),
replies: integer().notNull(),
danmakus: integer().notNull(),
shares: integer().notNull(),
}, (table) => [
index("idx_latest-video-snapshot_time").using("btree", table.time.asc().nullsLast().op("timestamptz_ops")),
index("idx_latest-video-snapshot_views").using("btree", table.views.asc().nullsLast().op("int4_ops")),
]);
export const videoSnapshot = pgTable(
"video_snapshot",
{
id: integer()
.default(sql`nextval('video_snapshot_id_seq'::regclass)`)
.notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" })
.default(sql`CURRENT_TIMESTAMP`)
.notNull(),
views: integer().notNull(),
coins: integer().notNull(),
likes: integer().notNull(),
favorites: integer().notNull(),
shares: integer().notNull(),
danmakus: integer().notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }).notNull(),
replies: integer().notNull()
},
(table) => [
index("idx_vid_snapshot_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
index("idx_vid_snapshot_time").using("btree", table.createdAt.asc().nullsLast().op("timestamptz_ops")),
index("idx_vid_snapshot_views").using("btree", table.views.asc().nullsLast().op("int4_ops")),
uniqueIndex("video_snapshot_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops"))
]
);
export const videoSnapshot = pgTable("video_snapshot", {
id: integer().default(sql`nextval('video_snapshot_id_seq'::regclass)`).notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
views: integer().notNull(),
coins: integer().notNull(),
likes: integer().notNull(),
favorites: integer().notNull(),
shares: integer().notNull(),
danmakus: integer().notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }).notNull(),
replies: integer().notNull(),
}, (table) => [
index("idx_vid_snapshot_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
index("idx_vid_snapshot_time").using("btree", table.createdAt.asc().nullsLast().op("timestamptz_ops")),
index("idx_vid_snapshot_views").using("btree", table.views.asc().nullsLast().op("int4_ops")),
uniqueIndex("video_snapshot_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
]);
export const snapshotSchedule = pgTable(
"snapshot_schedule",
{
id: bigserial({ mode: "bigint" }).notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }).notNull(),
type: text(),
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" })
.default(sql`CURRENT_TIMESTAMP`)
.notNull(),
startedAt: timestamp("started_at", { withTimezone: true, mode: "string" }),
finishedAt: timestamp("finished_at", { withTimezone: true, mode: "string" }),
status: text().default("pending").notNull()
},
(table) => [
index("idx_snapshot_schedule_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
index("idx_snapshot_schedule_started_at").using(
"btree",
table.startedAt.asc().nullsLast().op("timestamptz_ops")
),
index("idx_snapshot_schedule_status").using("btree", table.status.asc().nullsLast().op("text_ops")),
index("idx_snapshot_schedule_type").using("btree", table.type.asc().nullsLast().op("text_ops")),
uniqueIndex("snapshot_schedule_pkey").using("btree", table.id.asc().nullsLast().op("int8_ops"))
]
);
export const snapshotSchedule = pgTable("snapshot_schedule", {
id: bigserial({ mode: "bigint" }).notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }).notNull(),
type: text(),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
startedAt: timestamp("started_at", { withTimezone: true, mode: 'string' }),
finishedAt: timestamp("finished_at", { withTimezone: true, mode: 'string' }),
status: text().default('pending').notNull(),
}, (table) => [
index("idx_snapshot_schedule_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
index("idx_snapshot_schedule_started_at").using("btree", table.startedAt.asc().nullsLast().op("timestamptz_ops")),
index("idx_snapshot_schedule_status").using("btree", table.status.asc().nullsLast().op("text_ops")),
index("idx_snapshot_schedule_type").using("btree", table.type.asc().nullsLast().op("text_ops")),
uniqueIndex("snapshot_schedule_pkey").using("btree", table.id.asc().nullsLast().op("int8_ops")),
]);
export const songs = pgTable(
"songs",
{
id: integer()
.default(sql`nextval('songs_id_seq'::regclass)`)
.notNull(),
name: text(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }),
publishedAt: timestamp("published_at", { withTimezone: true, mode: "string" }),
duration: integer(),
type: smallint(),
romanizedName: text("romanized_name"),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
neteaseId: bigint("netease_id", { mode: "number" }),
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" })
.default(sql`CURRENT_TIMESTAMP`)
.notNull(),
updatedAt: timestamp("updated_at", { withTimezone: true, mode: "string" })
.default(sql`CURRENT_TIMESTAMP`)
.notNull(),
deleted: boolean().default(false).notNull()
},
(table) => [
index("idx_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
index("idx_hash_songs_aid").using("hash", table.aid.asc().nullsLast().op("int8_ops")),
index("idx_netease_id").using("btree", table.neteaseId.asc().nullsLast().op("int8_ops")),
index("idx_published_at").using("btree", table.publishedAt.asc().nullsLast().op("timestamptz_ops")),
index("idx_type").using("btree", table.type.asc().nullsLast().op("int2_ops")),
uniqueIndex("songs_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
uniqueIndex("unq_songs_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
uniqueIndex("unq_songs_netease_id").using("btree", table.neteaseId.asc().nullsLast().op("int8_ops"))
]
);
export const songs = pgTable("songs", {
id: integer().default(sql`nextval('songs_id_seq'::regclass)`).notNull(),
name: text(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }),
publishedAt: timestamp("published_at", { withTimezone: true, mode: 'string' }),
duration: integer(),
type: smallint(),
romanizedName: text("romanized_name"),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
neteaseId: bigint("netease_id", { mode: "number" }),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
deleted: boolean().default(false).notNull(),
}, (table) => [
index("idx_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
index("idx_hash_songs_aid").using("hash", table.aid.asc().nullsLast().op("int8_ops")),
index("idx_netease_id").using("btree", table.neteaseId.asc().nullsLast().op("int8_ops")),
index("idx_published_at").using("btree", table.publishedAt.asc().nullsLast().op("timestamptz_ops")),
index("idx_type").using("btree", table.type.asc().nullsLast().op("int2_ops")),
uniqueIndex("songs_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
uniqueIndex("unq_songs_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
uniqueIndex("unq_songs_netease_id").using("btree", table.neteaseId.asc().nullsLast().op("int8_ops")),
]);
export const viewsIncrementRate = pgTable("views_increment_rate", {
id: integer().default(sql`nextval('views_increment_rate_id_seq'::regclass)`).notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }).notNull(),
oldTime: timestamp("old_time", { withTimezone: true, mode: 'string' }).notNull(),
newTime: timestamp("new_time", { withTimezone: true, mode: 'string' }).notNull(),
oldViews: integer("old_views").notNull(),
newViews: integer("new_views").notNull(),
interval: interval().notNull(),
updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
speed: real(),
}, (table) => [
uniqueIndex("unq_views-increment-rate_aid_interval").using("btree", table.aid.asc().nullsLast().op("int8_ops"), table.interval.asc().nullsLast().op("int8_ops")),
uniqueIndex("views_increment_rate_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
]);
export const viewsIncrementRate = pgTable(
"views_increment_rate",
{
id: integer()
.default(sql`nextval('views_increment_rate_id_seq'::regclass)`)
.notNull(),
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
aid: bigint({ mode: "number" }).notNull(),
oldTime: timestamp("old_time", { withTimezone: true, mode: "string" }).notNull(),
newTime: timestamp("new_time", { withTimezone: true, mode: "string" }).notNull(),
oldViews: integer("old_views").notNull(),
newViews: integer("new_views").notNull(),
interval: interval().notNull(),
updatedAt: timestamp("updated_at", { withTimezone: true, mode: "string" })
.default(sql`CURRENT_TIMESTAMP`)
.notNull(),
speed: real()
},
(table) => [
uniqueIndex("unq_views-increment-rate_aid_interval").using(
"btree",
table.aid.asc().nullsLast().op("int8_ops"),
table.interval.asc().nullsLast().op("int8_ops")
),
uniqueIndex("views_increment_rate_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops"))
]
);

View File

@ -6,4 +6,4 @@ export type UserType = InferSelectModel<typeof users>;
export type SensitiveUserFields = "password" | "unqId";
export type BilibiliMetadataType = InferSelectModel<typeof bilibiliMetadata>;
export type VideoSnapshotType = InferSelectModel<typeof videoSnapshot>;
export type LatestVideoSnapshotType = InferSelectModel<typeof latestVideoSnapshot>;
export type LatestVideoSnapshotType = InferSelectModel<typeof latestVideoSnapshot>;

View File

@ -15,7 +15,9 @@ export default createHandler(() => (
{assets}
</head>
<body>
<div id="app" style="overflow-x: hidden">{children}</div>
<div id="app">
{children}
</div>
<div id="modal"></div>
{scripts}
</body>

View File

@ -29,4 +29,4 @@ export async function useCachedFetch<T>(
hooks.set(identifier, hook!);
updateContext(hooks);
return promise;
}
}

View File

@ -1,36 +1,36 @@
import { plugin } from 'postcss';
import { plugin } from "postcss";
export default plugin('postcss-calc-keyword-polyfill', () => {
const replacements = {
'pi': '3.141592653589793',
'e': '2.718281828459045',
'infinity': '1e308', // A very large number to simulate infinity
'-infinity': '-1e308', // A very small number to simulate -infinity
'nan': '0/0', // Division by zero in calc() results in NaN in modern browsers
};
export default plugin("postcss-calc-keyword-polyfill", () => {
const replacements = {
pi: "3.141592653589793",
e: "2.718281828459045",
infinity: "1e308", // A very large number to simulate infinity
"-infinity": "-1e308", // A very small number to simulate -infinity
nan: "0/0" // Division by zero in calc() results in NaN in modern browsers
};
// Regex to find the keywords, case-insensitive
const keywordRegex = new RegExp(`\\b(-?(${Object.keys(replacements).join('|')}))\\b`, 'gi');
// Regex to find the keywords, case-insensitive
const keywordRegex = new RegExp(`\\b(-?(${Object.keys(replacements).join("|")}))\\b`, "gi");
return (root) => {
root.walkDecls(decl => {
// Check if the declaration value contains calc()
if (decl.value.toLowerCase().includes('calc(')) {
decl.value = decl.value.replace(/calc\(([^)]+)\)/ig, (match, expression) => {
const newExpression = expression.replace(keywordRegex, (keyword) => {
const lowerKeyword = keyword.toLowerCase();
if (lowerKeyword in replacements) {
return replacements[lowerKeyword];
}
// Handle cases like -pi and -e
if (lowerKeyword.startsWith('-') && lowerKeyword.substring(1) in replacements) {
return `-${replacements[lowerKeyword.substring(1)]}`
}
return keyword; // Should not happen with the current regex, but as a fallback
});
return `calc(${newExpression})`;
});
}
});
};
});
return (root) => {
root.walkDecls((decl) => {
// Check if the declaration value contains calc()
if (decl.value.toLowerCase().includes("calc(")) {
decl.value = decl.value.replace(/calc\(([^)]+)\)/gi, (match, expression) => {
const newExpression = expression.replace(keywordRegex, (keyword) => {
const lowerKeyword = keyword.toLowerCase();
if (lowerKeyword in replacements) {
return replacements[lowerKeyword];
}
// Handle cases like -pi and -e
if (lowerKeyword.startsWith("-") && lowerKeyword.substring(1) in replacements) {
return `-${replacements[lowerKeyword.substring(1)]}`;
}
return keyword; // Should not happen with the current regex, but as a fallback
});
return `calc(${newExpression})`;
});
}
});
};
});

View File

@ -11,9 +11,7 @@ export default function NotFound() {
<main class="w-full h-[calc(100vh-6rem)] flex flex-col flex-grow items-center justify-center gap-8">
<h1 class="text-9xl font-thin">404</h1>
<p class="text-xl font-medium">(Дд)!?</p>
<A href="/">
</A>
<A href="/"></A>
</main>
</Layout>
);

View File

@ -26,9 +26,7 @@ export default function Info() {
<Typography.Body class="font-semibold" variant="small">
PUBLISHER
</Typography.Body>
<Typography.Body variant="large">
</Typography.Body>
<Typography.Body variant="large"></Typography.Body>
</div>
<div class="flex flex-col">
<Typography.Body class="font-semibold" variant="small">

View File

@ -31,13 +31,18 @@ export const route = {
const VideoCard: Component<VideoCardProps> = (props) => {
return (
<Card variant="outlined" class="w-64 h-52 grow-0 shrink-0 basis-64">
<CardMedia class="w-64 h-32 object-cover" round={false} src={props.video.bilibili_metadata.coverUrl || ""}
referrerpolicy="no-referrer" />
<Card variant="outlined" class="w-64 h-64 grow-0 shrink-0 basis-64">
<CardMedia
class="w-64 h-32 object-cover"
round={false}
src={props.video.bilibili_metadata.coverUrl || ""}
referrerpolicy="no-referrer"
/>
<CardContent class="py-3 px-4">
<Typography.Body variant="large">
<Typography.Body variant="large" class="text-wrap">
{props.video.bilibili_metadata.title}
</Typography.Body>
<span>{props.video.latest_video_snapshot.views} </span>
</CardContent>
</Card>
);
@ -53,15 +58,13 @@ export default function Home() {
<h2 class="text-2xl font-normal"></h2>
<div
class="flex overflow-x-auto overflow-y-hidden gap-4 whitespace-nowrap w-full
py-2 px-4 mt-2 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
py-2 px-4 mt-2 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
>
<Suspense fallback={<div>Loading...</div>}>
<For each={videos()}>{
(video) => <VideoCard video={video} />
}</For>
<For each={videos()}>{(video) => <VideoCard video={video} />}</For>
</Suspense>
</div>
</main>
</Layout>
);
}

View File

@ -97,7 +97,6 @@ export default function VideoInfoPage() {
};
});
return (
<Layout>
<main class="flex flex-col items-center min-h-screen gap-8 mt-10 md:mt-6 relative z-0 overflow-x-auto pb-8">

View File

@ -1,86 +1,261 @@
import { Layout } from "~/components/layout";
import { Button, Card, CardContent, CardMedia, ExtendedFAB, Typography } from "@m3-components/solid";
import { Button, Card, CardContent, CardMedia, ExtendedFAB, IconButton, Typography } from "@m3-components/solid";
import { TabSwitcher } from "~/components/song/TabSwitcher";
import { EditIcon, HomeIcon, MusicIcon } from "~/components/icons";
import { A } from "@solidjs/router";
import { RightArrow } from "~/components/icons/Arrow";
import { Component } from "solid-js";
import { LinkIcon } from "~/components/icons/Link";
import { StarBadge4, StarBadge6, StarBadge8 } from "~/components/icons/StarBadges";
import { HistoryIcon } from "~/components/icons/History";
const Staff: Component<{ name: string; role: string; num: number }> = (props) => {
return (
<A
href={`/author/${props.name}/info`}
class="group rounded-[1.25rem] hover:bg-surface-container h-16 flex items-center
px-4 justify-between"
>
<div class="ml-2 flex gap-5 lg:gap-4 grow w-full">
<span
class="font-[IPSD] font-medium text-[2rem] text-on-surface-variant"
style="
-webkit-text-stroke: var(--md-sys-color-on-surface-variant);
-webkit-text-stroke-width: 1.2px;
-webkit-text-fill-color: transparent;"
>
{props.num}
</span>
<div class="flex flex-col gap-[3px]">
<Typography.Body variant="large" class="text-on-surface font-medium">
{props.name}
</Typography.Body>
<Typography.Label variant="large" class="text-on-surface-variant">
{props.role}
</Typography.Label>
</div>
</div>
<IconButton class="text-on-surface-variant opacity-0 group-hover:opacity-80 duration-200">
<RightArrow />
</IconButton>
</A>
);
};
const Content: Component = () => {
return (
<>
<Card variant="outlined" class="w-full max-lg:rounded-none max-lg:border-none">
<div class="relative w-full overflow-hidden ">
<CardMedia
round={false}
src="https://i0.hdslb.com/bfs/archive/8ad220336f96e4d2ea05baada3bc04592d56b2a5.jpg"
referrerpolicy="no-referrer"
class="relative w-full z-[2]"
/>
<div class="h-10 lg:h-0" />
<CardMedia
round={false}
src="https://i0.hdslb.com/bfs/archive/8ad220336f96e4d2ea05baada3bc04592d56b2a5.jpg"
referrerpolicy="no-referrer"
class="w-full absolute lg:hidden top-10 z-[1]"
/>
<span
class="left-3 absolute bottom-14 z-10 text-sm text-white/95"
style="text-shadow:0px 1px 1px rgb(0 0 0 / 0.2) "
>
&
</span>
<span
class="left-3 absolute bottom-3 z-10 font-medium text-4xl text-white/90 "
style="text-shadow: 0px 1px 0px rgb(0 0 0 / 0.075), 0px 1px 1px rgb(0 0 0 / 0.075), 0px 2px 2px rgb(0 0 0 / 0.075)"
>
</span>
<span
class="font-[Inter] right-3 absolute bottom-10 z-10 text-xl text-white/95"
style="text-shadow: 0px 1px 2px rgb(0 0 0 / 0.1), 0px 3px 2px rgb(0 0 0 / 0.1), 0px 4px 8px rgb(0 0 0 / 0.1)"
>
4:54
</span>
<span
class="font-[Inter] right-3 absolute bottom-3 z-10 text-xl text-white/95"
style="text-shadow: 0px 1px 2px rgb(0 0 0 / 0.1), 0px 3px 2px rgb(0 0 0 / 0.1), 0px 4px 8px rgb(0 0 0 / 0.1)"
>
12,422
<span class="ml-1 text-sm"></span>
</span>
<div class="lg:hidden w-full gradient-blur !absolute !h-32">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
<CardContent class="max-lg:hidden px-7 py-6 flex flex-col gap-4">
<Typography.Display class="leading-[2.75rem]" variant="small">
</Typography.Display>
<div class="grid grid-cols-2 grid-rows-3 gap-2">
<div class="flex flex-col">
<Typography.Label class="text-on-surface-variant" variant="large">
</Typography.Label>
<Typography.Body variant="large">
<a href="#"></a>
</Typography.Body>
</div>
<div class="flex flex-col">
<Typography.Label class="text-on-surface-variant" variant="large">
</Typography.Label>
<Typography.Body variant="large">4:28</Typography.Body>
</div>
<div class="flex flex-col">
<Typography.Label class="text-on-surface-variant" variant="large">
稿
</Typography.Label>
<Typography.Body variant="large">
<a href="#"></a>
</Typography.Body>
</div>
<div class="flex flex-col">
<Typography.Label class="text-on-surface-variant" variant="large">
</Typography.Label>
<Typography.Body class="flex gap-2" variant="large">
<a href="https://www.bilibili.com/video/BV1eaq9Y3EVV/"></a>
<a href="https://vocadb.net/S/742394">VocaDB</a>
</Typography.Body>
</div>
<div class="flex flex-col">
<Typography.Label class="text-on-surface-variant" variant="large">
</Typography.Label>
<Typography.Body variant="large">2024-12-15 12:15:00</Typography.Body>
</div>
<div class="flex flex-col">
<Typography.Label class="text-on-surface-variant" variant="large">
</Typography.Label>
<Typography.Body variant="large">1.24 (12,422)</Typography.Body>
</div>
</div>
</CardContent>
</Card>
<div class="mx-4 my-6 lg:hidden">
<TabSwitcher />
</div>
<article class="mt-6">
<Typography.Headline class="mx-4" variant="medium"></Typography.Headline>
<Typography.Body class="mx-4 mt-2" variant="large">
<span class="font-medium"></span><a href="#"></a>
<span>
&VeryThinSpace;2024&VeryThinSpace;&VeryThinSpace;12&VeryThinSpace;&VeryThinSpace;15&VeryThinSpace;
</span>
稿
<a href="#"></a>&ThinSpace;<a href="#">Synthesizer V</a>&ThinSpace;
<span></span>
<span></span>, <a href="#"></a>
</Typography.Body>
<div class="h-7" />
<Typography.Headline class="mx-4" variant="medium"></Typography.Headline>
<div class="mt-3 mx-1">
<Staff num={1} name="洛凛" role="策划、作词" />
<Staff num={2} name="鱼柳" role="作曲、编曲" />
<Staff num={3} name="月华" role="混音" />
<Staff num={4} name="城西阿灵" role="视频" />
<Staff num={5} name="与嬴酌棠" role="题字" />
</div>
</article>
</>
);
};
const RightSideBar: Component = () => {
return (
<>
<div class="w-48 self-center 2xl:self-end flex justify-end mb-6">
<ExtendedFAB position="unset" size="small" elevation={false} text="编辑" color="primary">
<EditIcon />
</ExtendedFAB>
</div>
<TabSwitcher />
</>
);
};
const LeftSideBar: Component = () => {
return (
<>
<div class="inline-flex flex-col gap-4">
<A href="/">
<Button variant="outlined" class="gap-1 items-center" size="extra-small">
<HomeIcon class="w-5 h-5 text-xl -translate-y-0.25" />
<span></span>
</Button>
</A>
<A href="/songs">
<Button variant="outlined" class="gap-1 items-center" size="extra-small">
<MusicIcon class="w-5 h-5 text-xl" />
<span></span>
</Button>
</A>
<A href="/milestone/denndou/songs">
<Button variant="outlined" class="gap-1 items-center" size="extra-small">
<StarBadge4 class="w-5 h-5 text-xl" />
<span>殿</span>
</Button>
</A>
<A href="/milestone/densetsu/songs">
<Button variant="outlined" class="gap-1 items-center" size="extra-small">
<StarBadge6 class="w-5 h-5 text-xl" />
<span></span>
</Button>
</A>
<A href="/milestone/shinwa/songs">
<Button variant="outlined" class="gap-1 items-center" size="extra-small">
<StarBadge8 class="w-5 h-5 text-xl" />
<span></span>
</Button>
</A>
<A href="/singer/赤羽/songs">
<Button variant="outlined" class="gap-1 items-center" size="extra-small">
<LinkIcon class="w-5 h-5 text-xl" />
<span></span>
</Button>
</A>
<A href="/songs">
<Button variant="outlined" class="gap-1 items-center" size="extra-small">
<HistoryIcon class="w-5 h-5 text-xl" />
<span></span>
</Button>
</A>
</div>
</>
);
};
export default function Info() {
return (
<Layout>
<title></title>
<title> - - V </title>
<div
class="pt-12 px-4 w-full sm:w-120 sm:mx-auto lg:w-full 2xl:w-360 lg:grid lg:grid-cols-[1fr_560px_1fr]
class="pt-8 w-full sm:w-120 sm:mx-auto lg:w-full 2xl:w-360 lg:grid lg:grid-cols-[1fr_560px_1fr]
xl:grid-cols-[1fr_648px_1fr]"
>
<nav class="hidden pointer-events-none lg:block xl:pointer-events-auto pt-4">
<div class="inline-flex flex-col gap-2">
<A href="/">
<Button variant="outlined" class="gap-1 items-center" size="extra-small">
<HomeIcon class="w-5 h-5 text-xl -translate-y-0.25" />
<span></span>
</Button>
</A>
<A href="/songs">
<Button variant="outlined" class="gap-1 items-center" size="extra-small">
<MusicIcon class="w-5 h-5 text-xl" />
<span></span>
</Button>
</A>
</div>
<nav class="top-32 hidden lg:block pb-12 px-6 self-start sticky">
<LeftSideBar />
</nav>
<main>
<Card variant="outlined" class="w-full">
<CardMedia
round={false}
src="https://i0.hdslb.com/bfs/archive/8ad220336f96e4d2ea05baada3bc04592d56b2a5.jpg"
referrerpolicy="no-referrer"
class="w-full"
/>
<CardContent>
<Typography.Display class="mb-3" variant="small">
</Typography.Display>
<div class="grid grid-cols-2 grid-rows-3 gap-1">
<Typography.Body variant="large">稿</Typography.Body>
<Typography.Body variant="large">4:28</Typography.Body>
<Typography.Body variant="large"></Typography.Body>
<Typography.Body variant="large">
<span class="inline-flex gap-2">
<a href="https://www.bilibili.com/video/BV1eaq9Y3EVV/"></a>
<a href="https://vocadb.net/S/742394">VocaDB</a>
</span>
</Typography.Body>
<Typography.Body variant="large">2024-12-15 12:15:00</Typography.Body>
<Typography.Body variant="large">1.24 (12,422)</Typography.Body>
</div>
</CardContent>
</Card>
<div class="my-6 lg:hidden">
<TabSwitcher />
</div>
<article class="mt-6">
<Typography.Headline variant="medium"></Typography.Headline>
<Typography.Body class="mt-2" variant="large">
<span class="font-medium"></span><a href="#"></a>
<span>
&VeryThinSpace;2024&VeryThinSpace;&VeryThinSpace;12&VeryThinSpace;&VeryThinSpace;15&VeryThinSpace;
</span>
稿
<a href="#"></a>&ThinSpace;<a href="#">Synthesizer V</a>&ThinSpace;
<span></span>
<span></span>, <a href="#"></a>
</Typography.Body>
</article>
<main class="mb-24">
<Content />
</main>
<div class="hidden lg:flex flex-col px-6">
<div class="w-48 self-center 2xl:self-end flex justify-end mb-6">
<ExtendedFAB position="unset" size="small" elevation={false} text="编辑" color="primary">
<EditIcon />
</ExtendedFAB>
</div>
<TabSwitcher />
<div class="top-32 hidden lg:flex self-start sticky flex-col pb-12 px-6">
<RightSideBar />
</div>
</div>
</Layout>

View File

@ -0,0 +1,56 @@
function generateSpacing(nums: number[], divisor = 4): Record<number, string> {
return nums.reduce<Record<number, string>>((acc, n) => {
acc[n] = `${n / divisor}rem`;
return acc;
}, {});
}
/** @type {import('tailwindcss').Config} */
export default {
content: ["./src/**/*.{js,jsx,ts,tsx}"],
theme: {
extend: {
spacing: generateSpacing([360]),
colors: {
background: "var(--md-sys-color-background)",
"on-background": "var(--md-sys-color-on-background)",
surface: "var(--md-sys-color-surface)",
"surface-dim": "var(--md-sys-color-surface-dim)",
"surface-bright": "var(--md-sys-color-surface-bright)",
"surface-container-lowest": "var(--md-sys-color-surface-container-lowest)",
"surface-container-low": "var(--md-sys-color-surface-container-low)",
"surface-container": "var(--md-sys-color-surface-container)",
"surface-container-high": "var(--md-sys-color-surface-container-high)",
"surface-container-highest": "var(--md-sys-color-surface-container-highest)",
"on-surface": "var(--md-sys-color-on-surface)",
"surface-variant": "var(--md-sys-color-surface-variant)",
"on-surface-variant": "var(--md-sys-color-on-surface-variant)",
"inverse-surface": "var(--md-sys-color-inverse-surface)",
"inverse-on-surface": "var(--md-sys-color-inverse-on-surface)",
outline: "var(--md-sys-color-outline)",
"outline-variant": "var(--md-sys-color-outline-variant)",
shadow: "var(--md-sys-color-shadow)",
scrim: "var(--md-sys-color-scrim)",
"surface-tint": "var(--md-sys-color-surface-tint)",
primary: "var(--md-sys-color-primary)",
"on-primary": "var(--md-sys-color-on-primary)",
"primary-container": "var(--md-sys-color-primary-container)",
"on-primary-container": "var(--md-sys-color-on-primary-container)",
"inverse-primary": "var(--md-sys-color-inverse-primary)",
secondary: "var(--md-sys-color-secondary)",
"on-secondary": "var(--md-sys-color-on-secondary)",
"secondary-container": "var(--md-sys-color-secondary-container)",
"on-secondary-container": "var(--md-sys-color-on-secondary-container)",
tertiary: "var(--md-sys-color-tertiary)",
"on-tertiary": "var(--md-sys-color-on-tertiary)",
"tertiary-container": "var(--md-sys-color-tertiary-container)",
"on-tertiary-container": "var(--md-sys-color-on-tertiary-container)",
error: "var(--md-sys-color-error)",
"on-error": "var(--md-sys-color-on-error)",
"error-container": "var(--md-sys-color-error-container)",
"on-error-container": "var(--md-sys-color-on-error-container)"
}
}
},
plugins: []
};