From 26350628491cb39abf20c763250fd7dfe42fac54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Str=C3=B8m-Andersen?= Date: Thu, 1 Oct 2026 23:50:48 +0200 Subject: [PATCH 01/15] feat: Add Tailwind CSS --- app/index.css | 2 + package.json | 4 +- pnpm-lock.yaml | 620 +++++++++++++++++++++++++++++++++++++------------ vite.config.ts | 3 +- 4 files changed, 483 insertions(+), 146 deletions(-) diff --git a/app/index.css b/app/index.css index 9568450..8a81b3e 100644 --- a/app/index.css +++ b/app/index.css @@ -1,3 +1,5 @@ +@import "tailwindcss"; + :root { --theme-color: #0a2a3f; --background-color: #f6f3f1; diff --git a/package.json b/package.json index 27c59c6..f718d74 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,13 @@ "dependencies": { "@react-router/node": "^8.4.0", "@react-router/serve": "^8.4.0", + "@tailwindcss/vite": "^4.3.3", "@tanstack/react-query": "^5.104.0", + "isbot": "^5", "react": "^19.2.8", "react-dom": "^19.2.8", "react-router": "^8.4.0", - "isbot": "^5" + "tailwindcss": "^4.3.3" }, "devDependencies": { "@babel/core": "^7.29.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 70efbf7..9b5181e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@react-router/serve': specifier: ^8.4.0 version: 8.4.0(react-router@8.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(typescript@6.0.3) + '@tailwindcss/vite': + specifier: ^4.3.3 + version: 4.3.3(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0)) '@tanstack/react-query': specifier: ^5.104.0 version: 5.104.0(react@19.3.0) @@ -29,28 +32,31 @@ importers: react-router: specifier: ^8.4.0 version: 8.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + tailwindcss: + specifier: ^4.3.3 + version: 4.3.3 devDependencies: '@babel/core': specifier: ^7.29.7 version: 7.29.7 '@eslint-react/eslint-plugin': specifier: ^5.20.8 - version: 5.20.8(eslint@10.11.0)(typescript@6.0.3) + version: 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.11.0) + version: 10.0.1(eslint@10.11.0(jiti@2.7.0)) '@react-router/dev': specifier: ^8.4.0 - version: 8.4.0(@react-router/serve@8.4.0(react-router@8.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(typescript@6.0.3))(react-router@8.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(typescript@6.0.3)(vite@8.3.1(@types/node@24.19.0)) + version: 8.4.0(@react-router/serve@8.4.0(react-router@8.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(typescript@6.0.3))(react-router@8.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(typescript@6.0.3)(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0)) '@rolldown/plugin-babel': specifier: ^0.2.3 - version: 0.2.4(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.2.11)(vite@8.3.1(@types/node@24.19.0)) + version: 0.2.4(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.2.11)(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0)) '@testing-library/dom': specifier: ^10.4.2 version: 10.4.2 '@testing-library/jest-dom': specifier: ^7.0.1 - version: 7.0.1(@testing-library/dom@10.4.2)(vitest@5.0.2(@types/node@24.19.0)(jsdom@30.1.1)(vite@8.3.1(@types/node@24.19.0))) + version: 7.0.1(@testing-library/dom@10.4.2)(vitest@5.0.2(@types/node@24.19.0)(jsdom@30.1.1)(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0))) '@testing-library/react': specifier: ^16.3.3 version: 16.3.3(@testing-library/dom@10.4.2)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) @@ -71,19 +77,19 @@ importers: version: 19.3.0(@types/react@19.3.0) '@vitejs/plugin-react': specifier: ^6.1.1 - version: 6.1.1(@rolldown/plugin-babel@0.2.4(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.2.11)(vite@8.3.1(@types/node@24.19.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.3.1(@types/node@24.19.0)) + version: 6.1.1(@rolldown/plugin-babel@0.2.4(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.2.11)(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0)) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 eslint: specifier: ^10.10.0 - version: 10.11.0 + version: 10.11.0(jiti@2.7.0) eslint-plugin-react-hooks: specifier: ^7.1.1 - version: 7.1.1(eslint@10.11.0) + version: 7.1.1(eslint@10.11.0(jiti@2.7.0)) eslint-plugin-react-refresh: specifier: ^0.5.6 - version: 0.5.7(eslint@10.11.0) + version: 0.5.7(eslint@10.11.0(jiti@2.7.0)) globals: specifier: ^17.12.0 version: 17.12.0 @@ -98,13 +104,13 @@ importers: version: 6.0.3 typescript-eslint: specifier: ^8.69.0 - version: 8.70.1(eslint@10.11.0)(typescript@6.0.3) + version: 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) vite: specifier: ^8.3.0 - version: 8.3.1(@types/node@24.19.0) + version: 8.3.1(@types/node@24.19.0)(jiti@2.7.0) vitest: specifier: ^5.0.2 - version: 5.0.2(@types/node@24.19.0)(jsdom@30.1.1)(vite@8.3.1(@types/node@24.19.0)) + version: 5.0.2(@types/node@24.19.0)(jsdom@30.1.1)(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0)) packages: @@ -555,6 +561,100 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + '@tailwindcss/node@4.3.3': + resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==} + + '@tailwindcss/oxide-android-arm64@4.3.3': + resolution: {integrity: sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.3': + resolution: {integrity: sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.3': + resolution: {integrity: sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.3': + resolution: {integrity: sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': + resolution: {integrity: sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': + resolution: {integrity: sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': + resolution: {integrity: sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': + resolution: {integrity: sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.3.3': + resolution: {integrity: sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.3.3': + resolution: {integrity: sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': + resolution: {integrity: sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': + resolution: {integrity: sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.3': + resolution: {integrity: sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==} + engines: {node: '>= 20'} + + '@tailwindcss/vite@4.3.3': + resolution: {integrity: sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 || ^8 + '@tanstack/query-core@5.104.0': resolution: {integrity: sha512-JrC2r/JQlXt7khBSdUpsgxNvybzOg+aITa+ARRMlP2AFo93Y8vIqz077rp+e61mJetSZ0T6AJbwW1JHer1vrPQ==} @@ -953,6 +1053,10 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} + enhanced-resolve@5.26.0: + resolution: {integrity: sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw==} + engines: {node: '>=10.13.0'} + entities@8.1.0: resolution: {integrity: sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==} engines: {node: '>=20.19.0'} @@ -1175,6 +1279,9 @@ packages: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} @@ -1255,6 +1362,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1290,36 +1401,73 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + lightningcss-android-arm64@1.33.0: resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + lightningcss-darwin-arm64@1.33.0: resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + lightningcss-darwin-x64@1.33.0: resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + lightningcss-freebsd-x64@1.33.0: resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + lightningcss-linux-arm-gnueabihf@1.33.0: resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + lightningcss-linux-arm64-gnu@1.33.0: resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} engines: {node: '>= 12.0.0'} @@ -1327,6 +1475,13 @@ packages: os: [linux] libc: [glibc] + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + lightningcss-linux-arm64-musl@1.33.0: resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} engines: {node: '>= 12.0.0'} @@ -1334,6 +1489,13 @@ packages: os: [linux] libc: [musl] + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + lightningcss-linux-x64-gnu@1.33.0: resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} engines: {node: '>= 12.0.0'} @@ -1341,6 +1503,13 @@ packages: os: [linux] libc: [glibc] + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + lightningcss-linux-x64-musl@1.33.0: resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} engines: {node: '>= 12.0.0'} @@ -1348,18 +1517,34 @@ packages: os: [linux] libc: [musl] + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + lightningcss-win32-arm64-msvc@1.33.0: resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + lightningcss-win32-x64-msvc@1.33.0: resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + lightningcss@1.33.0: resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} engines: {node: '>= 12.0.0'} @@ -1382,6 +1567,9 @@ packages: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magic-string@1.4.2: resolution: {integrity: sha512-vG+rjFRj1PqdIBozIxAGMjPlOhaVe+GXpbttY/iSK7rGcJRMlwNJO7dcUwmUqkymsFLJiNGI06t4D7Fr7yRC9g==} @@ -1685,6 +1873,13 @@ packages: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} + tailwindcss@4.3.3: + resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + tinybench@6.2.0: resolution: {integrity: sha512-78U2TlB2CnVenajOFzf3BKSm0J6oz5L0NV7g32LCPccvYc0lbWvys4d3uUUCS2B1N8PAf2+aekR8i1KbC3HO7Q==} engines: {node: '>=20.0.0'} @@ -2082,94 +2277,94 @@ snapshots: '@csstools/css-tokenizer@4.0.2': {} - '@eslint-community/eslint-utils@4.10.1(eslint@10.11.0)': + '@eslint-community/eslint-utils@4.10.1(eslint@10.11.0(jiti@2.7.0))': dependencies: - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint-react/ast@5.20.8(eslint@10.11.0)(typescript@6.0.3)': + '@eslint-react/ast@5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.70.1 '@typescript-eslint/typescript-estree': 8.70.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) - eslint: 10.11.0 + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.11.0(jiti@2.7.0) string-ts: 2.3.1 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@eslint-react/core@5.20.8(eslint@10.11.0)(typescript@6.0.3)': + '@eslint-react/core@5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-react/ast': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/eslint': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/shared': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/var': 5.20.8(eslint@10.11.0)(typescript@6.0.3) + '@eslint-react/ast': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/var': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.70.1 '@typescript-eslint/types': 8.70.1 - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) - eslint: 10.11.0 + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.11.0(jiti@2.7.0) ts-pattern: 5.9.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@eslint-react/eslint-plugin@5.20.8(eslint@10.11.0)(typescript@6.0.3)': + '@eslint-react/eslint-plugin@5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-react/shared': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - eslint: 10.11.0 - eslint-plugin-react-dom: 5.20.8(eslint@10.11.0)(typescript@6.0.3) - eslint-plugin-react-jsx: 5.20.8(eslint@10.11.0)(typescript@6.0.3) - eslint-plugin-react-naming-convention: 5.20.8(eslint@10.11.0)(typescript@6.0.3) - eslint-plugin-react-rsc: 5.20.8(eslint@10.11.0)(typescript@6.0.3) - eslint-plugin-react-web-api: 5.20.8(eslint@10.11.0)(typescript@6.0.3) - eslint-plugin-react-x: 5.20.8(eslint@10.11.0)(typescript@6.0.3) + '@eslint-react/shared': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.11.0(jiti@2.7.0) + eslint-plugin-react-dom: 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-react-jsx: 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-react-naming-convention: 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-react-rsc: 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-react-web-api: 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-react-x: 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@eslint-react/eslint@5.20.8(eslint@10.11.0)(typescript@6.0.3)': + '@eslint-react/eslint@5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) - eslint: 10.11.0 + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.11.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@eslint-react/jsx@5.20.8(eslint@10.11.0)(typescript@6.0.3)': + '@eslint-react/jsx@5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-react/ast': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/eslint': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/shared': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/var': 5.20.8(eslint@10.11.0)(typescript@6.0.3) + '@eslint-react/ast': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/var': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/types': 8.70.1 - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) - eslint: 10.11.0 + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.11.0(jiti@2.7.0) ts-pattern: 5.9.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@eslint-react/shared@5.20.8(eslint@10.11.0)(typescript@6.0.3)': + '@eslint-react/shared@5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-react/eslint': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) - eslint: 10.11.0 + '@eslint-react/eslint': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.11.0(jiti@2.7.0) ts-pattern: 5.9.0 typescript: 6.0.3 zod: 4.6.5 transitivePeerDependencies: - supports-color - '@eslint-react/var@5.20.8(eslint@10.11.0)(typescript@6.0.3)': + '@eslint-react/var@5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-react/ast': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/eslint': 5.20.8(eslint@10.11.0)(typescript@6.0.3) + '@eslint-react/ast': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.70.1 '@typescript-eslint/types': 8.70.1 - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) - eslint: 10.11.0 + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.11.0(jiti@2.7.0) ts-pattern: 5.9.0 typescript: 6.0.3 transitivePeerDependencies: @@ -2191,9 +2386,9 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.11.0)': + '@eslint/js@10.0.1(eslint@10.11.0(jiti@2.7.0))': optionalDependencies: - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) '@eslint/object-schema@3.0.5': {} @@ -2249,7 +2444,7 @@ snapshots: '@oxc-project/types@0.151.0': {} - '@react-router/dev@8.4.0(@react-router/serve@8.4.0(react-router@8.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(typescript@6.0.3))(react-router@8.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(typescript@6.0.3)(vite@8.3.1(@types/node@24.19.0))': + '@react-router/dev@8.4.0(@react-router/serve@8.4.0(react-router@8.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(typescript@6.0.3))(react-router@8.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(typescript@6.0.3)(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0))': dependencies: '@babel/core': 7.29.7 '@babel/generator': 7.29.8 @@ -2275,7 +2470,7 @@ snapshots: semver: 7.8.5 tinyglobby: 0.2.17 valibot: 1.5.0(typescript@6.0.3) - vite: 8.3.1(@types/node@24.19.0) + vite: 8.3.1(@types/node@24.19.0)(jiti@2.7.0) optionalDependencies: '@react-router/serve': 8.4.0(react-router@8.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(typescript@6.0.3) typescript: 6.0.3 @@ -2361,17 +2556,85 @@ snapshots: '@rolldown/binding-win32-x64-msvc@1.2.11': optional: true - '@rolldown/plugin-babel@0.2.4(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.2.11)(vite@8.3.1(@types/node@24.19.0))': + '@rolldown/plugin-babel@0.2.4(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.2.11)(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0))': dependencies: '@babel/core': 7.29.7 picomatch: 4.0.7 rolldown: 1.2.11 optionalDependencies: '@babel/runtime': 7.29.7 - vite: 8.3.1(@types/node@24.19.0) + vite: 8.3.1(@types/node@24.19.0)(jiti@2.7.0) '@rolldown/pluginutils@1.0.1': {} + '@tailwindcss/node@4.3.3': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.26.0 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.3 + + '@tailwindcss/oxide-android-arm64@4.3.3': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.3': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.3': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.3': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.3': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': + optional: true + + '@tailwindcss/oxide@4.3.3': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-x64': 4.3.3 + '@tailwindcss/oxide-freebsd-x64': 4.3.3 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.3 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.3 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-x64-musl': 4.3.3 + '@tailwindcss/oxide-wasm32-wasi': 4.3.3 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 + + '@tailwindcss/vite@4.3.3(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0))': + dependencies: + '@tailwindcss/node': 4.3.3 + '@tailwindcss/oxide': 4.3.3 + tailwindcss: 4.3.3 + vite: 8.3.1(@types/node@24.19.0)(jiti@2.7.0) + '@tanstack/query-core@5.104.0': {} '@tanstack/react-query@5.104.0(react@19.3.0)': @@ -2390,7 +2653,7 @@ snapshots: picocolors: 1.1.1 pretty-format: 27.5.1 - '@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.2)(vitest@5.0.2(@types/node@24.19.0)(jsdom@30.1.1)(vite@8.3.1(@types/node@24.19.0)))': + '@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.2)(vitest@5.0.2(@types/node@24.19.0)(jsdom@30.1.1)(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0)))': dependencies: '@adobe/css-tools': 4.5.0 '@testing-library/dom': 10.4.2 @@ -2400,7 +2663,7 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 optionalDependencies: - vitest: 5.0.2(@types/node@24.19.0)(jsdom@30.1.1)(vite@8.3.1(@types/node@24.19.0)) + vitest: 5.0.2(@types/node@24.19.0)(jsdom@30.1.1)(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0)) '@testing-library/react@16.3.3(@testing-library/dom@10.4.2)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: @@ -2464,15 +2727,15 @@ snapshots: dependencies: csstype: 3.2.3 - '@typescript-eslint/eslint-plugin@8.70.1(@typescript-eslint/parser@8.70.1(eslint@10.11.0)(typescript@6.0.3))(eslint@10.11.0)(typescript@6.0.3)': + '@typescript-eslint/eslint-plugin@8.70.1(@typescript-eslint/parser@8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.70.1(eslint@10.11.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.70.1 - '@typescript-eslint/type-utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) + '@typescript-eslint/type-utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.70.1 - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) ignore: 7.0.10 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@6.0.3) @@ -2480,14 +2743,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.70.1(eslint@10.11.0)(typescript@6.0.3)': + '@typescript-eslint/parser@8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.70.1 '@typescript-eslint/types': 8.70.1 '@typescript-eslint/typescript-estree': 8.70.1(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.70.1 debug: 4.4.3 - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -2510,13 +2773,13 @@ snapshots: dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.70.1(eslint@10.11.0)(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.70.1 '@typescript-eslint/typescript-estree': 8.70.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) debug: 4.4.3 - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: @@ -2539,13 +2802,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.70.1(eslint@10.11.0)(typescript@6.0.3)': + '@typescript-eslint/utils@8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.10.1(eslint@10.11.0) + '@eslint-community/eslint-utils': 4.10.1(eslint@10.11.0(jiti@2.7.0)) '@typescript-eslint/scope-manager': 8.70.1 '@typescript-eslint/types': 8.70.1 '@typescript-eslint/typescript-estree': 8.70.1(typescript@6.0.3) - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -2555,22 +2818,22 @@ snapshots: '@typescript-eslint/types': 8.70.1 eslint-visitor-keys: 5.0.1 - '@vitejs/plugin-react@6.1.1(@rolldown/plugin-babel@0.2.4(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.2.11)(vite@8.3.1(@types/node@24.19.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.3.1(@types/node@24.19.0))': + '@vitejs/plugin-react@6.1.1(@rolldown/plugin-babel@0.2.4(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.2.11)(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.3.1(@types/node@24.19.0) + vite: 8.3.1(@types/node@24.19.0)(jiti@2.7.0) optionalDependencies: - '@rolldown/plugin-babel': 0.2.4(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.2.11)(vite@8.3.1(@types/node@24.19.0)) + '@rolldown/plugin-babel': 0.2.4(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.2.11)(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0)) babel-plugin-react-compiler: 1.0.0 - '@vitest/mocker@5.0.2(vite@8.3.1(@types/node@24.19.0))': + '@vitest/mocker@5.0.2(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0))': dependencies: '@jridgewell/trace-mapping': 0.3.31 '@vitest/spy': 5.0.2 estree-walker: 3.0.3 magic-string: 1.4.2 optionalDependencies: - vite: 8.3.1(@types/node@24.19.0) + vite: 8.3.1(@types/node@24.19.0)(jiti@2.7.0) '@vitest/spy@5.0.2': {} @@ -2780,6 +3043,11 @@ snapshots: encodeurl@2.0.0: {} + enhanced-resolve@5.26.0: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + entities@8.1.0: {} es-define-property@1.0.1: {} @@ -2798,110 +3066,110 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-plugin-react-dom@5.20.8(eslint@10.11.0)(typescript@6.0.3): + eslint-plugin-react-dom@5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/core': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/eslint': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/jsx': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/shared': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/var': 5.20.8(eslint@10.11.0)(typescript@6.0.3) + '@eslint-react/ast': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/core': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/jsx': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/var': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/types': 8.70.1 - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) compare-versions: 6.1.1 - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-hooks@7.1.1(eslint@10.11.0): + eslint-plugin-react-hooks@7.1.1(eslint@10.11.0(jiti@2.7.0)): dependencies: '@babel/core': 7.29.7 '@babel/parser': 7.29.9 - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) hermes-parser: 0.25.1 zod: 4.6.5 zod-validation-error: 4.0.2(zod@4.6.5) transitivePeerDependencies: - supports-color - eslint-plugin-react-jsx@5.20.8(eslint@10.11.0)(typescript@6.0.3): + eslint-plugin-react-jsx@5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/core': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/eslint': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/jsx': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/shared': 5.20.8(eslint@10.11.0)(typescript@6.0.3) + '@eslint-react/ast': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/core': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/jsx': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/types': 8.70.1 - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) - eslint: 10.11.0 + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.11.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-naming-convention@5.20.8(eslint@10.11.0)(typescript@6.0.3): + eslint-plugin-react-naming-convention@5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/core': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/eslint': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/shared': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/var': 5.20.8(eslint@10.11.0)(typescript@6.0.3) + '@eslint-react/ast': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/core': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/var': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/types': 8.70.1 - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) - eslint: 10.11.0 + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.11.0(jiti@2.7.0) ts-pattern: 5.9.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-refresh@0.5.7(eslint@10.11.0): + eslint-plugin-react-refresh@0.5.7(eslint@10.11.0(jiti@2.7.0)): dependencies: - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) - eslint-plugin-react-rsc@5.20.8(eslint@10.11.0)(typescript@6.0.3): + eslint-plugin-react-rsc@5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/core': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/eslint': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/shared': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/var': 5.20.8(eslint@10.11.0)(typescript@6.0.3) + '@eslint-react/ast': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/core': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/var': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/types': 8.70.1 - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) - eslint: 10.11.0 + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.11.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-web-api@5.20.8(eslint@10.11.0)(typescript@6.0.3): + eslint-plugin-react-web-api@5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/core': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/eslint': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/shared': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/var': 5.20.8(eslint@10.11.0)(typescript@6.0.3) + '@eslint-react/ast': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/core': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/var': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/types': 8.70.1 - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) - eslint: 10.11.0 + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.11.0(jiti@2.7.0) ts-pattern: 5.9.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-x@5.20.8(eslint@10.11.0)(typescript@6.0.3): + eslint-plugin-react-x@5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/core': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/eslint': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/jsx': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/shared': 5.20.8(eslint@10.11.0)(typescript@6.0.3) - '@eslint-react/var': 5.20.8(eslint@10.11.0)(typescript@6.0.3) + '@eslint-react/ast': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/core': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/jsx': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/var': 5.20.8(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.70.1 - '@typescript-eslint/type-utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) + '@typescript-eslint/type-utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/types': 8.70.1 '@typescript-eslint/typescript-estree': 8.70.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) compare-versions: 6.1.1 - eslint: 10.11.0 + eslint: 10.11.0(jiti@2.7.0) string-ts: 2.3.1 ts-api-utils: 2.5.0(typescript@6.0.3) ts-pattern: 5.9.0 @@ -2920,9 +3188,9 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.11.0: + eslint@10.11.0(jiti@2.7.0): dependencies: - '@eslint-community/eslint-utils': 4.10.1(eslint@10.11.0) + '@eslint-community/eslint-utils': 4.10.1(eslint@10.11.0(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.23.5 '@eslint/config-helpers': 0.7.0 @@ -2952,6 +3220,8 @@ snapshots: minimatch: 10.2.6 natural-compare: 1.4.0 optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 transitivePeerDependencies: - supports-color @@ -3093,6 +3363,8 @@ snapshots: gopd@1.2.0: {} + graceful-fs@4.2.11: {} + has-symbols@1.1.0: {} hashery@1.5.1: @@ -3157,6 +3429,8 @@ snapshots: isexe@2.0.0: {} + jiti@2.7.0: {} + js-tokens@4.0.0: {} jsdom@30.1.1: @@ -3201,39 +3475,88 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lightningcss-android-arm64@1.32.0: + optional: true + lightningcss-android-arm64@1.33.0: optional: true + lightningcss-darwin-arm64@1.32.0: + optional: true + lightningcss-darwin-arm64@1.33.0: optional: true + lightningcss-darwin-x64@1.32.0: + optional: true + lightningcss-darwin-x64@1.33.0: optional: true + lightningcss-freebsd-x64@1.32.0: + optional: true + lightningcss-freebsd-x64@1.33.0: optional: true + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + lightningcss-linux-arm-gnueabihf@1.33.0: optional: true + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + lightningcss-linux-arm64-gnu@1.33.0: optional: true + lightningcss-linux-arm64-musl@1.32.0: + optional: true + lightningcss-linux-arm64-musl@1.33.0: optional: true + lightningcss-linux-x64-gnu@1.32.0: + optional: true + lightningcss-linux-x64-gnu@1.33.0: optional: true + lightningcss-linux-x64-musl@1.32.0: + optional: true + lightningcss-linux-x64-musl@1.33.0: optional: true + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + lightningcss-win32-arm64-msvc@1.33.0: optional: true + lightningcss-win32-x64-msvc@1.32.0: + optional: true + lightningcss-win32-x64-msvc@1.33.0: optional: true + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + lightningcss@1.33.0: dependencies: detect-libc: 2.1.2 @@ -3264,6 +3587,10 @@ snapshots: lz-string@1.5.0: {} + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + magic-string@1.4.2: dependencies: '@jridgewell/sourcemap-codec': 1.6.0 @@ -3567,6 +3894,10 @@ snapshots: dependencies: min-indent: 1.0.1 + tailwindcss@4.3.3: {} + + tapable@2.3.3: {} + tinybench@6.2.0: {} tinyexec@1.3.1: {} @@ -3608,13 +3939,13 @@ snapshots: media-typer: 1.1.1 mime-types: 3.0.2 - typescript-eslint@8.70.1(eslint@10.11.0)(typescript@6.0.3): + typescript-eslint@8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.70.1(@typescript-eslint/parser@8.70.1(eslint@10.11.0)(typescript@6.0.3))(eslint@10.11.0)(typescript@6.0.3) - '@typescript-eslint/parser': 8.70.1(eslint@10.11.0)(typescript@6.0.3) + '@typescript-eslint/eslint-plugin': 8.70.1(@typescript-eslint/parser@8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/typescript-estree': 8.70.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.70.1(eslint@10.11.0)(typescript@6.0.3) - eslint: 10.11.0 + '@typescript-eslint/utils': 8.70.1(eslint@10.11.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.11.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -3643,7 +3974,7 @@ snapshots: vary@1.1.2: {} - vite@8.3.1(@types/node@24.19.0): + vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0): dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 @@ -3653,11 +3984,12 @@ snapshots: optionalDependencies: '@types/node': 24.19.0 fsevents: 2.3.3 + jiti: 2.7.0 - vitest@5.0.2(@types/node@24.19.0)(jsdom@30.1.1)(vite@8.3.1(@types/node@24.19.0)): + vitest@5.0.2(@types/node@24.19.0)(jsdom@30.1.1)(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0)): dependencies: '@types/chai': 5.2.3 - '@vitest/mocker': 5.0.2(vite@8.3.1(@types/node@24.19.0)) + '@vitest/mocker': 5.0.2(vite@8.3.1(@types/node@24.19.0)(jiti@2.7.0)) chai: 6.2.2 es-module-lexer: 2.3.2 expect-type: 1.4.0 @@ -3668,7 +4000,7 @@ snapshots: tinybench: 6.2.0 tinyexec: 1.3.1 tinyglobby: 0.2.17 - vite: 8.3.1(@types/node@24.19.0) + vite: 8.3.1(@types/node@24.19.0)(jiti@2.7.0) why-is-node-running: 3.2.2 optionalDependencies: '@types/node': 24.19.0 diff --git a/vite.config.ts b/vite.config.ts index 2f11994..7c2f097 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,11 +1,12 @@ import { reactRouter } from "@react-router/dev/vite"; import { defineConfig } from "vitest/config"; +import tailwindcss from "@tailwindcss/vite"; // https://vite.dev/config/ export default defineConfig({ // React Router does not work in Vitest's environment. // See GitHub discussion: https://github.com/remix-run/react-router/discussions/12655 - plugins: [!process.env.VITEST && reactRouter()], + plugins: [!process.env.VITEST && reactRouter(), tailwindcss()], resolve: { tsconfigPaths: true, }, From 14b8a5899585a6c66e24ed5221189d941277feb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Str=C3=B8m-Andersen?= Date: Fri, 2 Oct 2026 00:00:59 +0200 Subject: [PATCH 02/15] refactor: remove css reset handled by Tailwind Preflight Tailwind Preflight already provides many of these reset styles. See https://tailwindcss.com/docs/preflight --- app/index.css | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/app/index.css b/app/index.css index 8a81b3e..e72ef51 100644 --- a/app/index.css +++ b/app/index.css @@ -9,18 +9,6 @@ --muted: #6b7280; --muted-background: rgba(255, 255, 255, 0.25); } - -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -ul, -ol { - list-style: none; -} - body { background-color: var(--background-color); display: flex; From 9b16105111a52b8651669284c67c34f6c01f60ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Str=C3=B8m-Andersen?= Date: Fri, 2 Oct 2026 02:16:43 +0200 Subject: [PATCH 03/15] refactor: convert index.css tokens to Tailwind @theme and @layer Define every color as a theme variable so dark mode can be added later if we want. --- app/index.css | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/app/index.css b/app/index.css index e72ef51..04f4f32 100644 --- a/app/index.css +++ b/app/index.css @@ -1,20 +1,38 @@ @import "tailwindcss"; -:root { - --theme-color: #0a2a3f; - --background-color: #f6f3f1; - --footer-background-color: #2b2a2a; - --border-color: #ebe9e6; - --border-radius: 8px; - --muted: #6b7280; - --muted-background: rgba(255, 255, 255, 0.25); +@theme { + --color-theme: #0a2a3f; + --color-background: #f6f3f1; + --color-footer: #2b2a2a; + --color-surface: #ffffff; + --color-border: #ebe9e6; + --color-muted: #6b7280; + --color-muted-background: rgba(255, 255, 255, 0.25); + --color-control-hover: #f3f4f6; + --color-control-hover-border: #9ca3af; + --color-success: #129b44; + --color-disabled: #9ca3af; + --radius-base: 8px; + --font-sans: "Open Sans", sans-serif; } + +@layer base { + h1, + h2, + h3, + h4, + h5, + h6 { + font-weight: 700; + } +} + body { - background-color: var(--background-color); + background-color: var(--color-background); display: flex; flex-direction: column; min-height: 100svh; - font-family: "Open Sans", sans-serif; + font-family: var(--font-sans); } main { From 9fd75a9e25dc5e30e7f43b3f3496dd76c3073348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Str=C3=B8m-Andersen?= Date: Fri, 2 Oct 2026 02:19:27 +0200 Subject: [PATCH 04/15] refactor: convert BookCard styles to Tailwind --- app/components/BookCard/BookCard.module.css | 39 --------------------- app/components/BookCard/BookCard.tsx | 9 +++-- 2 files changed, 4 insertions(+), 44 deletions(-) delete mode 100644 app/components/BookCard/BookCard.module.css diff --git a/app/components/BookCard/BookCard.module.css b/app/components/BookCard/BookCard.module.css deleted file mode 100644 index 9186421..0000000 --- a/app/components/BookCard/BookCard.module.css +++ /dev/null @@ -1,39 +0,0 @@ -.book-card { - position: relative; - display: flex; - flex-direction: column; - height: 100%; - box-sizing: border-box; - background-color: white; - border-radius: var(--border-radius); - border: 1px solid var(--border-color); -} - -.book-card-link { - all: unset; - cursor: pointer; - - display: flex; - flex: 1; - flex-direction: column; - width: 100%; - height: 100%; - - box-sizing: border-box; - padding: 24px; - border-radius: var(--border-radius); - - &:hover { - border: 1px solid var(--theme-color); - } -} - -.info { - margin-top: 16px; - font-size: 0.9rem; -} - -.title { - margin-bottom: 8px; - font-size: 1rem; -} diff --git a/app/components/BookCard/BookCard.tsx b/app/components/BookCard/BookCard.tsx index c080c35..807030c 100644 --- a/app/components/BookCard/BookCard.tsx +++ b/app/components/BookCard/BookCard.tsx @@ -1,4 +1,3 @@ -import styles from "./BookCard.module.css"; import { BookCover } from "~/components/BookCover/BookCover"; import { FavoriteButton } from "~/components/FavoriteButton/FavoriteButton"; import type { Book } from "~/api/types"; @@ -12,19 +11,19 @@ function BookCard({ book }: BookCardProps) { const [searchParams] = useSearchParams(); return ( -
+
-
-

{book.title}

+
+

{book.title}

{book.author.join(", ")}

{book.publishedYear ?? "Unknown"}

From 936277b1cf4afa4a3e2b48caeba93ea87ae5b48d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Str=C3=B8m-Andersen?= Date: Fri, 2 Oct 2026 02:19:44 +0200 Subject: [PATCH 05/15] refactor: convert BookCover styles to Tailwind --- app/components/BookCover/BookCover.module.css | 18 ------------------ app/components/BookCover/BookCover.tsx | 7 ++++--- 2 files changed, 4 insertions(+), 21 deletions(-) delete mode 100644 app/components/BookCover/BookCover.module.css diff --git a/app/components/BookCover/BookCover.module.css b/app/components/BookCover/BookCover.module.css deleted file mode 100644 index 16c1d33..0000000 --- a/app/components/BookCover/BookCover.module.css +++ /dev/null @@ -1,18 +0,0 @@ -.cover-image { - width: 100%; - padding: 12px 24px; - object-fit: contain; -} - -.cover-placeholder { - display: flex; - align-items: center; - justify-content: center; - aspect-ratio: 2 / 3; - margin: 12px 24px; - background-color: var(--background-color); - border-radius: var(--border-radius); - color: var(--theme-color); - font-size: 0.875rem; - text-align: center; -} diff --git a/app/components/BookCover/BookCover.tsx b/app/components/BookCover/BookCover.tsx index f71bca2..316b342 100644 --- a/app/components/BookCover/BookCover.tsx +++ b/app/components/BookCover/BookCover.tsx @@ -1,4 +1,3 @@ -import styles from "./BookCover.module.css"; import type { Book } from "~/api/types"; interface BookCoverProps { @@ -10,10 +9,12 @@ function BookCover({ book }: BookCoverProps) { {`Book ) : ( -

No cover available

+

+ No cover available +

); } From 1eda0894e947398cffe41347191b8b21b6e2ce23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Str=C3=B8m-Andersen?= Date: Fri, 2 Oct 2026 02:19:59 +0200 Subject: [PATCH 06/15] refactor: convert FavoriteButton styles to Tailwind --- .../FavoriteButton/FavoriteButton.module.css | 25 ------------------- .../FavoriteButton/FavoriteButton.tsx | 3 +-- 2 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 app/components/FavoriteButton/FavoriteButton.module.css diff --git a/app/components/FavoriteButton/FavoriteButton.module.css b/app/components/FavoriteButton/FavoriteButton.module.css deleted file mode 100644 index 5d17f2e..0000000 --- a/app/components/FavoriteButton/FavoriteButton.module.css +++ /dev/null @@ -1,25 +0,0 @@ -.favorite-button { - position: absolute; - display: flex; - align-items: center; - justify-content: center; - top: 8px; - right: 8px; - background-color: white; - color: var(--theme-color); - border: 1px solid var(--border-color); - border-radius: var(--border-radius); - width: 32px; - height: 32px; - font-size: 1.5rem; - cursor: pointer; - - &:hover { - border: 1px solid var(--theme-color); - } -} - -.favorite-button-active { - color: green; - border: 1px solid green; -} diff --git a/app/components/FavoriteButton/FavoriteButton.tsx b/app/components/FavoriteButton/FavoriteButton.tsx index f2acc15..5422231 100644 --- a/app/components/FavoriteButton/FavoriteButton.tsx +++ b/app/components/FavoriteButton/FavoriteButton.tsx @@ -1,5 +1,4 @@ import { useState } from "react"; -import styles from "./FavoriteButton.module.css"; import { CheckIcon } from "~/components/icons/CheckIcon"; import type { Book } from "~/api/types"; @@ -31,7 +30,7 @@ function FavoriteButton({ book }: FavoriteButtonProps) { return (
From f2ca28e8750db37ce9ce066227a182facd40b301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Str=C3=B8m-Andersen?= Date: Fri, 2 Oct 2026 02:22:13 +0200 Subject: [PATCH 13/15] refactor: convert home styles to Tailwind --- app/routes/home.module.css | 29 ----------------------------- app/routes/home.tsx | 9 ++++----- 2 files changed, 4 insertions(+), 34 deletions(-) delete mode 100644 app/routes/home.module.css diff --git a/app/routes/home.module.css b/app/routes/home.module.css deleted file mode 100644 index eda8216..0000000 --- a/app/routes/home.module.css +++ /dev/null @@ -1,29 +0,0 @@ -.book-grid { - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: 16px; - justify-content: center; - max-width: 1200px; - margin: 0 auto; - padding: 40px 40px; - - @media only screen and (max-width: 1200px) { - grid-template-columns: repeat(3, 1fr); - } - - @media only screen and (max-width: 1000px) { - grid-template-columns: repeat(2, 1fr); - } - - @media only screen and (max-width: 600px) { - grid-template-columns: 1fr; - } -} - -.message { - display: grid; - place-items: center; - min-height: 50svh; - padding: 40px; - text-align: center; -} diff --git a/app/routes/home.tsx b/app/routes/home.tsx index 4793694..36530e6 100644 --- a/app/routes/home.tsx +++ b/app/routes/home.tsx @@ -1,7 +1,6 @@ import { Pagination } from "~/components/Pagination/Pagination"; import { SEARCH_LIMIT } from "~/api/openLibrary"; import { useBooks } from "~/api/useBooks"; -import styles from "./home.module.css"; import { SearchBar } from "~/components/SearchBar/SearchBar"; import { BookCard } from "~/components/BookCard/BookCard"; import { useBookSearchParams } from "~/api/useBookSearchParams"; @@ -26,7 +25,7 @@ export default function HomePage() { return (
-

+

Loading books...

@@ -37,7 +36,7 @@ export default function HomePage() { return (
-

+

Error: {error.message}

@@ -48,7 +47,7 @@ export default function HomePage() { return (
-

+

No books found for this search

@@ -58,7 +57,7 @@ export default function HomePage() { return (
-
    +
      {data.books.map((book) => (
    • From 84f06ac081d90869f4fa72b4cf6cb92952575d86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Str=C3=B8m-Andersen?= Date: Fri, 2 Oct 2026 02:22:36 +0200 Subject: [PATCH 14/15] refactor: convert selectedBook styles to Tailwind --- app/routes/book/selectedBook.module.css | 119 ------------------------ app/routes/book/selectedBook.tsx | 27 +++--- 2 files changed, 11 insertions(+), 135 deletions(-) delete mode 100644 app/routes/book/selectedBook.module.css diff --git a/app/routes/book/selectedBook.module.css b/app/routes/book/selectedBook.module.css deleted file mode 100644 index 666bdd8..0000000 --- a/app/routes/book/selectedBook.module.css +++ /dev/null @@ -1,119 +0,0 @@ -.info-text { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100%; -} - -.book-details { - display: flex; - flex-direction: row; - max-width: 1200px; - margin: 0 auto; - margin-top: 60px; - padding: 40px; - gap: 10px; - - @media only screen and (max-width: 900px) { - flex-direction: column; - } -} - -.go-back-button { - all: unset; - position: absolute; - top: -42px; - left: 0; - background-color: white; - border: 1px solid var(--border-color); - border-radius: var(--border-radius); - padding: 8px 16px; - cursor: pointer; - font-size: 0.925rem; - - &:hover { - border-color: var(--theme-color); - } -} - -.browse-buttons { - position: absolute; - top: -42px; - right: 0; - display: flex; - gap: 8px; -} - -.browse-button { - all: unset; - background-color: white; - border: 1px solid var(--border-color); - border-radius: var(--border-radius); - padding: 8px 16px; - cursor: pointer; - font-size: 0.925rem; - - &:hover:not(:disabled) { - border-color: var(--theme-color); - } - - &:disabled { - color: #9ca3af; - cursor: not-allowed; - } -} - -.browse-button-disabled { - all: unset; - background-color: white; - border: 1px solid var(--border-color); - border-radius: var(--border-radius); - padding: 8px 16px; - cursor: not-allowed; - font-size: 0.925rem; - color: #9ca3af; -} - -.cover-section { - position: relative; - flex: 0 0 40%; - padding: 30px; - background-color: white; - border-radius: var(--border-radius); - border: 1px solid var(--border-color); - display: flex; - align-items: center; - justify-content: center; -} - -.info { - flex: 1; - padding: 30px; - background-color: white; - border-radius: var(--border-radius); - border: 1px solid var(--border-color); -} - -.title { - margin-bottom: 8px; - font-size: 1.5rem; -} - -.description { - margin-top: 16px; - padding-top: 16px; - border-top: 1px solid var(--border-color); - line-height: 1.5; -} - -@media only screen and (max-width: 900px) and (min-width: 750px) { - .cover-section img { - margin: 50px; - } -} -@media only screen and (max-width: 1000px) and (min-width: 901px) { - .cover-section { - padding: 15px; - } -} diff --git a/app/routes/book/selectedBook.tsx b/app/routes/book/selectedBook.tsx index b155ce6..1707088 100644 --- a/app/routes/book/selectedBook.tsx +++ b/app/routes/book/selectedBook.tsx @@ -1,5 +1,4 @@ import type { Route } from "./+types/selectedBook"; -import styles from "./selectedBook.module.css"; import { BookCover } from "~/components/BookCover/BookCover"; import { FavoriteButton } from "~/components/FavoriteButton/FavoriteButton"; import { useBookDescription } from "~/api/useBookDescription"; @@ -34,7 +33,7 @@ export default function SelectedBookPage({ params }: Route.ComponentProps) { if (isBooksPending || isDescriptionPending) { return ( -
      +

      Loading Book Details

      The requested book details are currently being loaded.

      @@ -43,7 +42,7 @@ export default function SelectedBookPage({ params }: Route.ComponentProps) { if (!books || !book) { return ( -
      +

      Book Not Found

      The requested book could not be found.

      @@ -58,23 +57,21 @@ export default function SelectedBookPage({ params }: Route.ComponentProps) { return (
      -
      -
      +
      +
      Go back -
      -
      -

      {book.title}

      +
      +

      {book.title}

      {book.author.join(", ")}

      {book.publishedYear ?? "Unknown"}

      -

      Description

      +

      Description

      {descriptionText}

      From bebcbcb2f9814b71c69a8ca5f8931523c3f253ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Str=C3=B8m-Andersen?= Date: Fri, 2 Oct 2026 02:23:15 +0200 Subject: [PATCH 15/15] refactor: add CircleQuestionMark styles to Tailwind --- app/components/icons/CircleQuestionMark.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/components/icons/CircleQuestionMark.tsx b/app/components/icons/CircleQuestionMark.tsx index b8bee2d..cc7f3e0 100644 --- a/app/components/icons/CircleQuestionMark.tsx +++ b/app/components/icons/CircleQuestionMark.tsx @@ -5,6 +5,7 @@ function CircleQuestionMark() { return (