diff --git a/frontend/package.json b/frontend/package.json index aac0c47..a2ff9ad 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,9 +12,15 @@ "@astrojs/preact": "^4.0.1", "@astrojs/sitemap": "^3.2.1", "@astrojs/tailwind": "^5.1.4", + "@tailwindcss/typography": "^0.5.15", "astro": "^5.1.1", + "clsx": "^2.1.1", "preact": "^10.25.3", + "tailwind-merge": "^2.5.5", "tailwindcss": "^3.4.17" }, - "packageManager": "pnpm@9.15.1+sha512.1acb565e6193efbebda772702950469150cf12bcc764262e7587e71d19dc98a423dff9536e57ea44c49bdf790ff694e83c27be5faa23d67e0c033b583be4bfcf" + "packageManager": "pnpm@9.15.1+sha512.1acb565e6193efbebda772702950469150cf12bcc764262e7587e71d19dc98a423dff9536e57ea44c49bdf790ff694e83c27be5faa23d67e0c033b583be4bfcf", + "devDependencies": { + "sass-embedded": "^1.83.0" + } } diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index f05bd43..119feae 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -10,22 +10,35 @@ importers: dependencies: '@astrojs/preact': specifier: ^4.0.1 - version: 4.0.1(@babel/core@7.26.0)(jiti@2.4.2)(preact@10.25.3)(yaml@2.6.1) + version: 4.0.1(@babel/core@7.26.0)(jiti@2.4.2)(preact@10.25.3)(sass-embedded@1.83.0)(yaml@2.6.1) '@astrojs/sitemap': specifier: ^3.2.1 version: 3.2.1 '@astrojs/tailwind': specifier: ^5.1.4 - version: 5.1.4(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(typescript@5.7.2)(yaml@2.6.1))(tailwindcss@3.4.17) + version: 5.1.4(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass-embedded@1.83.0)(typescript@5.7.2)(yaml@2.6.1))(tailwindcss@3.4.17) + '@tailwindcss/typography': + specifier: ^0.5.15 + version: 0.5.15(tailwindcss@3.4.17) astro: specifier: ^5.1.1 - version: 5.1.1(jiti@2.4.2)(rollup@4.29.1)(typescript@5.7.2)(yaml@2.6.1) + version: 5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass-embedded@1.83.0)(typescript@5.7.2)(yaml@2.6.1) + clsx: + specifier: ^2.1.1 + version: 2.1.1 preact: specifier: ^10.25.3 version: 10.25.3 + tailwind-merge: + specifier: ^2.5.5 + version: 2.5.5 tailwindcss: specifier: ^3.4.17 version: 3.4.17 + devDependencies: + sass-embedded: + specifier: ^1.83.0 + version: 1.83.0 packages: @@ -158,6 +171,9 @@ packages: resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} engines: {node: '>=6.9.0'} + '@bufbuild/protobuf@2.2.3': + resolution: {integrity: sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg==} + '@emnapi/runtime@1.3.1': resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} @@ -831,6 +847,11 @@ packages: '@shikijs/vscode-textmate@9.3.1': resolution: {integrity: sha512-79QfK1393x9Ho60QFyLti+QfdJzRQCVLFb97kOIV7Eo9vQU/roINgk7m24uv0a7AUvN//RDH36FLjjK48v0s9g==} + '@tailwindcss/typography@0.5.15': + resolution: {integrity: sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20' + '@types/cookie@0.6.0': resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} @@ -964,6 +985,9 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer-builder@0.2.0: + resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} + camelcase-css@2.0.1: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} @@ -1028,6 +1052,9 @@ packages: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + colorjs.io@0.5.2: + resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -1287,6 +1314,10 @@ packages: h3@1.13.0: resolution: {integrity: sha512-vFEAu/yf8UMUcB4s43OaDaigcqpQd14yanmOsn+NcRX3/guSKncyE2rOYhq8RIchgJrPSs/QiIddnTTR1ddiAg==} + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -1342,6 +1373,9 @@ packages: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} + immutable@5.0.3: + resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==} + import-meta-resolve@4.1.0: resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==} @@ -1466,6 +1500,15 @@ packages: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} + lodash.castarray@4.4.0: + resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -1831,6 +1874,10 @@ packages: peerDependencies: postcss: ^8.2.14 + postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + postcss-selector-parser@6.1.2: resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} engines: {node: '>=4'} @@ -1944,6 +1991,134 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + + sass-embedded-android-arm64@1.83.0: + resolution: {integrity: sha512-GBiCvM4a2rkWBLdYDxI6XYnprfk5U5c81g69RC2X6kqPuzxzx8qTArQ9M6keFK4+iDQ5N9QTwFCr0KbZTn+ZNQ==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [android] + + sass-embedded-android-arm@1.83.0: + resolution: {integrity: sha512-uwFSXzJlfbd4Px189xE5l+cxN8+TQpXdQgJec7TIrb4HEY7imabtpYufpVdqUVwT1/uiis5V4+qIEC4Vl5XObQ==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [android] + + sass-embedded-android-ia32@1.83.0: + resolution: {integrity: sha512-5ATPdGo2SICqAhiJl/Z8KQ23zH4sGgobGgux0TnrNtt83uHZ+r+To/ubVJ7xTkZxed+KJZnIpolGD8dQyQqoTg==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [android] + + sass-embedded-android-riscv64@1.83.0: + resolution: {integrity: sha512-aveknUOB8GZewOzVn2Uwk+DKcncTR50Q6vtzslNMGbYnxtgQNHzy8A1qVEviNUruex+pHofppeMK4iMPFAbiEQ==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [android] + + sass-embedded-android-x64@1.83.0: + resolution: {integrity: sha512-WqIay/72ncyf9Ph4vS742J3a73wZihWmzFUwpn1OD6lme1Aj4eWzWIve5IVnlTEJgcZcDHu6ECID9IZgehJKoA==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [android] + + sass-embedded-darwin-arm64@1.83.0: + resolution: {integrity: sha512-XQl9QqgxFFIPm/CzHhmppse5o9ocxrbaAdC2/DAnlAqvYWBBtgFqPjGoYlej13h9SzfvNoogx+y9r+Ap+e+hYg==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [darwin] + + sass-embedded-darwin-x64@1.83.0: + resolution: {integrity: sha512-ERQ7Tvp1kFOW3ux4VDFIxb7tkYXHYc+zJpcrbs0hzcIO5ilIRU2tIOK1OrNwrFO6Qxyf7AUuBwYKLAtIU/Nz7g==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [darwin] + + sass-embedded-linux-arm64@1.83.0: + resolution: {integrity: sha512-syEAVTJt4qhaMLxrSwOWa46zdqHJdnqJkLUK+t9aCr8xqBZLPxSUeIGji76uOehQZ1C+KGFj6n9xstHN6wzOJw==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + + sass-embedded-linux-arm@1.83.0: + resolution: {integrity: sha512-baG9RYBJxUFmqwDNC9h9ZFElgJoyO3jgHGjzEZ1wHhIS9anpG+zZQvO8bHx3dBpKEImX+DBeLX+CxsFR9n81gQ==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + + sass-embedded-linux-ia32@1.83.0: + resolution: {integrity: sha512-RRBxQxMpoxu5+XcSSc6QR/o9asEwUzR8AbCS83RaXcdTIHTa/CccQsiAoDDoPlRsMTLqnzs0LKL4CfOsf7zBbA==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [linux] + + sass-embedded-linux-musl-arm64@1.83.0: + resolution: {integrity: sha512-Y7juhPHClUO2H5O+u+StRy6SEAcwZ+hTEk5WJdEmo1Bb1gDtfHvJaWB/iFZJ2tW0W1e865AZeUrC4OcOFjyAQA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + + sass-embedded-linux-musl-arm@1.83.0: + resolution: {integrity: sha512-Yc7u2TelCfBab+PRob9/MNJFh3EooMiz4urvhejXkihTiKSHGCv5YqDdtWzvyb9tY2Jb7YtYREVuHwfdVn3dTQ==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + + sass-embedded-linux-musl-ia32@1.83.0: + resolution: {integrity: sha512-arQeYwGmwXV8byx5G1PtSzZWW1jbkfR5qrIHMEbTFSAvAxpqjgSvCvrHMOFd73FcMxVaYh4BX9LQNbKinkbEdg==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [linux] + + sass-embedded-linux-musl-riscv64@1.83.0: + resolution: {integrity: sha512-E6uzlIWz59rut+Z3XR6mLG915zNzv07ISvj3GUNZENdHM7dF8GQ//ANoIpl5PljMQKp89GnYdvo6kj2gnaBf/g==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + + sass-embedded-linux-musl-x64@1.83.0: + resolution: {integrity: sha512-eAMK6tyGqvqr21r9g8BnR3fQc1rYFj85RGduSQ3xkITZ6jOAnOhuU94N5fwRS852Hpws0lXhET+7JHXgg3U18w==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + + sass-embedded-linux-riscv64@1.83.0: + resolution: {integrity: sha512-Ojpi78pTv02sy2fUYirRGXHLY3fPnV/bvwuC2i5LwPQw2LpCcFyFTtN0c5h4LJDk9P6wr+/ZB/JXU8tHIOlK+Q==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + + sass-embedded-linux-x64@1.83.0: + resolution: {integrity: sha512-3iLjlXdoPfgZRtX4odhRvka1BQs5mAXqfCtDIQBgh/o0JnGPzJIWWl9bYLpHxK8qb+uyVBxXYgXpI0sCzArBOw==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + + sass-embedded-win32-arm64@1.83.0: + resolution: {integrity: sha512-iOHw/8/t2dlTW3lOFwG5eUbiwhEyGWawivlKWJ8lkXH7fjMpVx2VO9zCFAm8RvY9xOHJ9sf1L7g5bx3EnNP9BQ==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [win32] + + sass-embedded-win32-ia32@1.83.0: + resolution: {integrity: sha512-2PxNXJ8Pad4geVcTXY4rkyTr5AwbF8nfrCTDv0ulbTvPhzX2mMKEGcBZUXWn5BeHZTBc6whNMfS7d5fQXR9dDQ==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [win32] + + sass-embedded-win32-x64@1.83.0: + resolution: {integrity: sha512-muBXkFngM6eLTNqOV0FQi7Dv9s+YRQ42Yem26mosdan/GmJQc81deto6uDTgrYn+bzFNmiXcOdfm+0MkTWK3OQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [win32] + + sass-embedded@1.83.0: + resolution: {integrity: sha512-/8cYZeL39evUqe0o//193na51Q1VWZ61qhxioQvLJwOtWIrX+PgNhCyD8RSuTtmzc4+6+waFZf899bfp/MCUwA==} + engines: {node: '>=16.0.0'} + hasBin: true + sax@1.4.1: resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} @@ -2046,14 +2221,29 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + sync-child-process@1.0.2: + resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} + engines: {node: '>=16.0.0'} + + sync-message-port@1.1.3: + resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==} + engines: {node: '>=16.0.0'} + system-architecture@0.1.0: resolution: {integrity: sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==} engines: {node: '>=18'} + tailwind-merge@2.5.5: + resolution: {integrity: sha512-0LXunzzAZzo0tEPxV3I297ffKZPlKDrjj7NXphC8V5ak9yHC5zRmxnOe2m/Rd/7ivsOMJe3JZ2JVocoDdQTRBA==} + tailwindcss@3.4.17: resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} engines: {node: '>=14.0.0'} @@ -2221,6 +2411,9 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + varint@6.0.0: + resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} + vfile-location@5.0.3: resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} @@ -2391,16 +2584,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@astrojs/preact@4.0.1(@babel/core@7.26.0)(jiti@2.4.2)(preact@10.25.3)(yaml@2.6.1)': + '@astrojs/preact@4.0.1(@babel/core@7.26.0)(jiti@2.4.2)(preact@10.25.3)(sass-embedded@1.83.0)(yaml@2.6.1)': dependencies: '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-react-jsx-development': 7.25.9(@babel/core@7.26.0) - '@preact/preset-vite': 2.8.2(@babel/core@7.26.0)(preact@10.25.3)(vite@6.0.5(jiti@2.4.2)(yaml@2.6.1)) + '@preact/preset-vite': 2.8.2(@babel/core@7.26.0)(preact@10.25.3)(vite@6.0.5(jiti@2.4.2)(sass-embedded@1.83.0)(yaml@2.6.1)) '@preact/signals': 1.3.1(preact@10.25.3) babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.26.0) preact: 10.25.3 preact-render-to-string: 6.5.12(preact@10.25.3) - vite: 6.0.5(jiti@2.4.2)(yaml@2.6.1) + vite: 6.0.5(jiti@2.4.2)(sass-embedded@1.83.0)(yaml@2.6.1) transitivePeerDependencies: - '@babel/core' - '@types/node' @@ -2426,9 +2619,9 @@ snapshots: stream-replace-string: 2.0.0 zod: 3.24.1 - '@astrojs/tailwind@5.1.4(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(typescript@5.7.2)(yaml@2.6.1))(tailwindcss@3.4.17)': + '@astrojs/tailwind@5.1.4(astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass-embedded@1.83.0)(typescript@5.7.2)(yaml@2.6.1))(tailwindcss@3.4.17)': dependencies: - astro: 5.1.1(jiti@2.4.2)(rollup@4.29.1)(typescript@5.7.2)(yaml@2.6.1) + astro: 5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass-embedded@1.83.0)(typescript@5.7.2)(yaml@2.6.1) autoprefixer: 10.4.20(postcss@8.4.49) postcss: 8.4.49 postcss-load-config: 4.0.2(postcss@8.4.49) @@ -2575,6 +2768,8 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 + '@bufbuild/protobuf@2.2.3': {} + '@emnapi/runtime@1.3.1': dependencies: tslib: 2.8.1 @@ -2904,12 +3099,12 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@preact/preset-vite@2.8.2(@babel/core@7.26.0)(preact@10.25.3)(vite@6.0.5(jiti@2.4.2)(yaml@2.6.1))': + '@preact/preset-vite@2.8.2(@babel/core@7.26.0)(preact@10.25.3)(vite@6.0.5(jiti@2.4.2)(sass-embedded@1.83.0)(yaml@2.6.1))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-react-jsx-development': 7.25.9(@babel/core@7.26.0) - '@prefresh/vite': 2.4.6(preact@10.25.3)(vite@6.0.5(jiti@2.4.2)(yaml@2.6.1)) + '@prefresh/vite': 2.4.6(preact@10.25.3)(vite@6.0.5(jiti@2.4.2)(sass-embedded@1.83.0)(yaml@2.6.1)) '@rollup/pluginutils': 4.2.1 babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.26.0) debug: 4.4.0 @@ -2919,7 +3114,7 @@ snapshots: resolve: 1.22.10 source-map: 0.7.4 stack-trace: 1.0.0-pre2 - vite: 6.0.5(jiti@2.4.2)(yaml@2.6.1) + vite: 6.0.5(jiti@2.4.2)(sass-embedded@1.83.0)(yaml@2.6.1) transitivePeerDependencies: - preact - supports-color @@ -2939,7 +3134,7 @@ snapshots: '@prefresh/utils@1.2.0': {} - '@prefresh/vite@2.4.6(preact@10.25.3)(vite@6.0.5(jiti@2.4.2)(yaml@2.6.1))': + '@prefresh/vite@2.4.6(preact@10.25.3)(vite@6.0.5(jiti@2.4.2)(sass-embedded@1.83.0)(yaml@2.6.1))': dependencies: '@babel/core': 7.26.0 '@prefresh/babel-plugin': 0.5.1 @@ -2947,7 +3142,7 @@ snapshots: '@prefresh/utils': 1.2.0 '@rollup/pluginutils': 4.2.1 preact: 10.25.3 - vite: 6.0.5(jiti@2.4.2)(yaml@2.6.1) + vite: 6.0.5(jiti@2.4.2)(sass-embedded@1.83.0)(yaml@2.6.1) transitivePeerDependencies: - supports-color @@ -3048,6 +3243,14 @@ snapshots: '@shikijs/vscode-textmate@9.3.1': {} + '@tailwindcss/typography@0.5.15(tailwindcss@3.4.17)': + dependencies: + lodash.castarray: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.17 + '@types/cookie@0.6.0': {} '@types/debug@4.1.12': @@ -3115,7 +3318,7 @@ snapshots: array-iterate@2.0.1: {} - astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(typescript@5.7.2)(yaml@2.6.1): + astro@5.1.1(jiti@2.4.2)(rollup@4.29.1)(sass-embedded@1.83.0)(typescript@5.7.2)(yaml@2.6.1): dependencies: '@astrojs/compiler': 2.10.3 '@astrojs/internal-helpers': 0.4.2 @@ -3167,8 +3370,8 @@ snapshots: unist-util-visit: 5.0.0 unstorage: 1.14.1 vfile: 6.0.3 - vite: 6.0.5(jiti@2.4.2)(yaml@2.6.1) - vitefu: 1.0.4(vite@6.0.5(jiti@2.4.2)(yaml@2.6.1)) + vite: 6.0.5(jiti@2.4.2)(sass-embedded@1.83.0)(yaml@2.6.1) + vitefu: 1.0.4(vite@6.0.5(jiti@2.4.2)(sass-embedded@1.83.0)(yaml@2.6.1)) which-pm: 3.0.0 xxhash-wasm: 1.1.0 yargs-parser: 21.1.1 @@ -3264,6 +3467,8 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.1(browserslist@4.24.3) + buffer-builder@0.2.0: {} + camelcase-css@2.0.1: {} camelcase@8.0.0: {} @@ -3326,6 +3531,8 @@ snapshots: color-string: 1.9.1 optional: true + colorjs.io@0.5.2: {} + comma-separated-tokens@2.0.3: {} commander@4.1.1: {} @@ -3602,6 +3809,8 @@ snapshots: uncrypto: 0.1.3 unenv: 1.10.0 + has-flag@4.0.0: {} + hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -3705,6 +3914,8 @@ snapshots: human-signals@5.0.0: {} + immutable@5.0.3: {} + import-meta-resolve@4.1.0: {} iron-webcrypto@1.2.1: {} @@ -3817,6 +4028,12 @@ snapshots: dependencies: p-locate: 4.1.0 + lodash.castarray@4.4.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.merge@4.6.2: {} + longest-streak@3.1.0: {} lru-cache@10.4.3: {} @@ -4340,6 +4557,11 @@ snapshots: postcss: 8.4.49 postcss-selector-parser: 6.1.2 + postcss-selector-parser@6.0.10: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss-selector-parser@6.1.2: dependencies: cssesc: 3.0.0 @@ -4524,6 +4746,102 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rxjs@7.8.1: + dependencies: + tslib: 2.8.1 + + sass-embedded-android-arm64@1.83.0: + optional: true + + sass-embedded-android-arm@1.83.0: + optional: true + + sass-embedded-android-ia32@1.83.0: + optional: true + + sass-embedded-android-riscv64@1.83.0: + optional: true + + sass-embedded-android-x64@1.83.0: + optional: true + + sass-embedded-darwin-arm64@1.83.0: + optional: true + + sass-embedded-darwin-x64@1.83.0: + optional: true + + sass-embedded-linux-arm64@1.83.0: + optional: true + + sass-embedded-linux-arm@1.83.0: + optional: true + + sass-embedded-linux-ia32@1.83.0: + optional: true + + sass-embedded-linux-musl-arm64@1.83.0: + optional: true + + sass-embedded-linux-musl-arm@1.83.0: + optional: true + + sass-embedded-linux-musl-ia32@1.83.0: + optional: true + + sass-embedded-linux-musl-riscv64@1.83.0: + optional: true + + sass-embedded-linux-musl-x64@1.83.0: + optional: true + + sass-embedded-linux-riscv64@1.83.0: + optional: true + + sass-embedded-linux-x64@1.83.0: + optional: true + + sass-embedded-win32-arm64@1.83.0: + optional: true + + sass-embedded-win32-ia32@1.83.0: + optional: true + + sass-embedded-win32-x64@1.83.0: + optional: true + + sass-embedded@1.83.0: + dependencies: + '@bufbuild/protobuf': 2.2.3 + buffer-builder: 0.2.0 + colorjs.io: 0.5.2 + immutable: 5.0.3 + rxjs: 7.8.1 + supports-color: 8.1.1 + sync-child-process: 1.0.2 + varint: 6.0.0 + optionalDependencies: + sass-embedded-android-arm: 1.83.0 + sass-embedded-android-arm64: 1.83.0 + sass-embedded-android-ia32: 1.83.0 + sass-embedded-android-riscv64: 1.83.0 + sass-embedded-android-x64: 1.83.0 + sass-embedded-darwin-arm64: 1.83.0 + sass-embedded-darwin-x64: 1.83.0 + sass-embedded-linux-arm: 1.83.0 + sass-embedded-linux-arm64: 1.83.0 + sass-embedded-linux-ia32: 1.83.0 + sass-embedded-linux-musl-arm: 1.83.0 + sass-embedded-linux-musl-arm64: 1.83.0 + sass-embedded-linux-musl-ia32: 1.83.0 + sass-embedded-linux-musl-riscv64: 1.83.0 + sass-embedded-linux-musl-x64: 1.83.0 + sass-embedded-linux-riscv64: 1.83.0 + sass-embedded-linux-x64: 1.83.0 + sass-embedded-win32-arm64: 1.83.0 + sass-embedded-win32-ia32: 1.83.0 + sass-embedded-win32-x64: 1.83.0 + sax@1.4.1: {} semver@6.3.1: {} @@ -4647,10 +4965,22 @@ snapshots: pirates: 4.0.6 ts-interface-checker: 0.1.13 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} + sync-child-process@1.0.2: + dependencies: + sync-message-port: 1.1.3 + + sync-message-port@1.1.3: {} + system-architecture@0.1.0: {} + tailwind-merge@2.5.5: {} + tailwindcss@3.4.17: dependencies: '@alloc/quick-lru': 5.2.0 @@ -4702,8 +5032,7 @@ snapshots: optionalDependencies: typescript: 5.7.2 - tslib@2.8.1: - optional: true + tslib@2.8.1: {} type-fest@4.30.2: {} @@ -4804,6 +5133,8 @@ snapshots: util-deprecate@1.0.2: {} + varint@6.0.0: {} + vfile-location@5.0.3: dependencies: '@types/unist': 3.0.3 @@ -4819,7 +5150,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite@6.0.5(jiti@2.4.2)(yaml@2.6.1): + vite@6.0.5(jiti@2.4.2)(sass-embedded@1.83.0)(yaml@2.6.1): dependencies: esbuild: 0.24.0 postcss: 8.4.49 @@ -4827,11 +5158,12 @@ snapshots: optionalDependencies: fsevents: 2.3.3 jiti: 2.4.2 + sass-embedded: 1.83.0 yaml: 2.6.1 - vitefu@1.0.4(vite@6.0.5(jiti@2.4.2)(yaml@2.6.1)): + vitefu@1.0.4(vite@6.0.5(jiti@2.4.2)(sass-embedded@1.83.0)(yaml@2.6.1)): optionalDependencies: - vite: 6.0.5(jiti@2.4.2)(yaml@2.6.1) + vite: 6.0.5(jiti@2.4.2)(sass-embedded@1.83.0)(yaml@2.6.1) web-namespaces@2.0.1: {} diff --git a/frontend/public/noise.png b/frontend/public/noise.png new file mode 100644 index 0000000..0cad3f3 Binary files /dev/null and b/frontend/public/noise.png differ diff --git a/frontend/public/notify.wav b/frontend/public/notify.wav new file mode 100644 index 0000000..237be13 Binary files /dev/null and b/frontend/public/notify.wav differ diff --git a/frontend/src/components/Badge.tsx b/frontend/src/components/Badge.tsx new file mode 100644 index 0000000..4178b4b --- /dev/null +++ b/frontend/src/components/Badge.tsx @@ -0,0 +1,48 @@ +import { cn, type ClassValue } from "@/util"; +import type { JSX } from "astro/jsx-runtime"; + +type BadgeProps = { + className?: ClassValue; + onClick?: () => void; + children: JSX.Element | JSX.Element[]; + screenReaderLabel?: string; +}; + +const Badge = ({ + className, + children, + onClick, + screenReaderLabel, +}: BadgeProps) => { + return ( + + {children} + + + ); +}; + +export default Badge; diff --git a/frontend/src/components/StatefulDemo.tsx b/frontend/src/components/StatefulDemo.tsx new file mode 100644 index 0000000..426c741 --- /dev/null +++ b/frontend/src/components/StatefulDemo.tsx @@ -0,0 +1,48 @@ +import Badge from "@/components/Badge"; +import { useState } from "preact/hooks"; + +type StatefulDemoProps = { + class?: string; +}; + +type SessionData = { + id: string; + downloads: string[]; +}; + +const StatefulDemo = ({ class: className }: StatefulDemoProps) => { + const [session, setSession] = useState({ + id: "0x59AF5", + downloads: ["0xABF4"], + }); + + return ( +
+

+ This demo uses websockets to communicate between the server and the + browser. Each download gets a unique identifier bound to the user + session. +
+ Your session is{" "} + {session?.id ?? "loading"}. You + have {session?.downloads.length}{" "} + known downloads. +

+
+ {session?.downloads.map((download) => ( + + {download} + + ))} +
+
+ ); +}; + +export default StatefulDemo; diff --git a/frontend/src/globals.scss b/frontend/src/globals.scss new file mode 100644 index 0000000..a1780b8 --- /dev/null +++ b/frontend/src/globals.scss @@ -0,0 +1,81 @@ +@tailwind base; + +@import url("https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Source+Serif+4:ital,opsz,wght@0,8..60,200..900;1,8..60,200..900&display=swap"); + +.noise::after { + background-image: url("/noise.png"); + position: fixed; + z-index: 10; + left: 0; + right: 0; + top: 0; + bottom: 0; + opacity: 50%; + content: " "; + pointer-events: none; +} + +.noise-card { + @apply bg-zinc-800; + &::before { + position: absolute; + z-index: 30; + left: 0; + right: 0; + top: 0; + bottom: 0; + content: " "; + pointer-events: none; + background-image: url("/noise.png"); + background-position-x: 66px; + // background-color: rgba(255, 255, 255, 6%); + opacity: 80%; + // filter: brightness(100%); + // background: linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)), url("/noise.png"); + // #202020; + } +} + +html, +body { + @apply overflow-x-hidden; + background-color: #151413; + color: #bab1a8; + margin: 0; + width: 100%; + height: 100%; +} + +@layer base { + * { + /* @apply border-border; */ + } + body { + /* @apply bg-background text-foreground; */ + } + + ul, + ol { + list-style: revert; + } + /* NEW CODE */ + /* width */ + ::-webkit-scrollbar { + @apply w-2 rounded-lg; + } + + /* Track */ + ::-webkit-scrollbar-track { + @apply bg-zinc-700 rounded-lg; + } + + /* Handle */ + ::-webkit-scrollbar-thumb { + @apply bg-zinc-500 rounded-xl; + } + + /* Handle on hover */ + ::-webkit-scrollbar-thumb:hover { + @apply bg-zinc-400 rounded-lg; + } +} diff --git a/frontend/src/layouts/Base.astro b/frontend/src/layouts/Base.astro index cc718d6..ed6aae5 100644 --- a/frontend/src/layouts/Base.astro +++ b/frontend/src/layouts/Base.astro @@ -6,16 +6,7 @@ Dynamic Preauth - + - - diff --git a/frontend/src/pages/index.astro b/frontend/src/pages/index.astro index 5e67cc2..9f8e458 100644 --- a/frontend/src/pages/index.astro +++ b/frontend/src/pages/index.astro @@ -1,6 +1,51 @@ --- -// import Welcome from '@/components/Welcome.astro'; -import Layout from "@/layouts/Base.astro"; +import Base from "@/layouts/Base.astro"; +import StatefulDemo from "@/components/StatefulDemo.tsx"; +import "@/globals.scss"; --- - + +
+
+
+

+ Dynamic Preauthentication +

+
+

+ This is a proof of concept for what I'm calling Dynamic Preauthentication. Essentially, a precompiled executable keeps a constant time + string that has a known (or easily extracted) pattern. +

+

+ When a download is requested, the server can generate and embed a + token that allows the application to authenticate the user + immediately. +

+

+ This would allow users to skip the initial login process and + immediately start using the application. It could also be used to + track downloads, hint at user behaviors, or create unique user + experiences. +

+
+
+
+ Demo +
+
+ +
+
+
+ diff --git a/frontend/src/util.ts b/frontend/src/util.ts new file mode 100644 index 0000000..0230a35 --- /dev/null +++ b/frontend/src/util.ts @@ -0,0 +1,7 @@ +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export { type ClassValue }; +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/frontend/tailwind.config.mjs b/frontend/tailwind.config.mjs index 19f0614..d9adcf5 100644 --- a/frontend/tailwind.config.mjs +++ b/frontend/tailwind.config.mjs @@ -1,8 +1,13 @@ /** @type {import('tailwindcss').Config} */ export default { - content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'], - theme: { - extend: {}, - }, - plugins: [], -} + content: ["./src/**/*.{astro,html,js,jsx,ts,tsx}"], + theme: { + extend: { + fontFamily: { + bebas: ["Bebas Neue", "sans-serif"], + sans: ["Inter", "sans-serif"], + }, + }, + }, + plugins: [require("@tailwindcss/typography")], +};