diff --git a/package-lock.json b/package-lock.json index a80fe0b..3a1885c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "devDependencies": { "@electron/rebuild": "^4.0.4", "@eslint/js": "^9.39.1", + "@tailwindcss/vite": "^4.3.0", "@types/node": "^24.10.1", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", @@ -39,6 +40,7 @@ "postcss": "^8.5.6", "postcss-preset-mantine": "^1.18.0", "postcss-simple-vars": "^7.0.1", + "tailwindcss": "^4.3.0", "typescript": "~5.9.3", "typescript-eslint": "^8.48.0", "vite": "^7.3.1" @@ -2082,6 +2084,278 @@ "react": ">= 16" } }, + "node_modules/@tailwindcss/node": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz", + "integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.21.0", + "jiti": "^2.6.1", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.0" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.0.tgz", + "integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.0", + "@tailwindcss/oxide-darwin-arm64": "4.3.0", + "@tailwindcss/oxide-darwin-x64": "4.3.0", + "@tailwindcss/oxide-freebsd-x64": "4.3.0", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", + "@tailwindcss/oxide-linux-x64-musl": "4.3.0", + "@tailwindcss/oxide-wasm32-wasi": "4.3.0", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.0.tgz", + "integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.0.tgz", + "integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.0.tgz", + "integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.0.tgz", + "integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.0.tgz", + "integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.0.tgz", + "integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.0.tgz", + "integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.0.tgz", + "integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.0.tgz", + "integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.0.tgz", + "integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.10.0", + "@emnapi/runtime": "^1.10.0", + "@emnapi/wasi-threads": "^1.2.1", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz", + "integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.0.tgz", + "integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.0.tgz", + "integrity": "sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.3.0", + "@tailwindcss/oxide": "4.3.0", + "tailwindcss": "4.3.0" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7 || ^8" + } + }, "node_modules/@tanstack/query-core": { "version": "5.90.20", "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.20.tgz", @@ -3856,6 +4130,16 @@ "node": ">=0.4.0" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-node": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", @@ -4246,6 +4530,20 @@ "once": "^1.4.0" } }, + "node_modules/enhanced-resolve": { + "version": "5.21.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.3.tgz", + "integrity": "sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -6098,6 +6396,267 @@ "node": ">= 0.8.0" } }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "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" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -6176,6 +6735,16 @@ "yallist": "^3.0.2" } }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", @@ -8359,6 +8928,27 @@ "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", "license": "MIT" }, + "node_modules/tailwindcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz", + "integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/tar": { "version": "7.5.9", "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.9.tgz", diff --git a/package.json b/package.json index feb356d..e48bd70 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "devDependencies": { "@electron/rebuild": "^4.0.4", "@eslint/js": "^9.39.1", + "@tailwindcss/vite": "^4.3.0", "@types/node": "^24.10.1", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", @@ -48,6 +49,7 @@ "postcss": "^8.5.6", "postcss-preset-mantine": "^1.18.0", "postcss-simple-vars": "^7.0.1", + "tailwindcss": "^4.3.0", "typescript": "~5.9.3", "typescript-eslint": "^8.48.0", "vite": "^7.3.1" diff --git a/src/ui/App.css b/src/ui/App.css deleted file mode 100644 index b9d355d..0000000 --- a/src/ui/App.css +++ /dev/null @@ -1,42 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/src/ui/App.tsx b/src/ui/App.tsx index eabf09f..a152118 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -66,7 +66,7 @@ function App() { - + diff --git a/src/ui/components/Header/Header.tsx b/src/ui/components/Header/Header.tsx index a10b3ed..4e5a9e5 100644 --- a/src/ui/components/Header/Header.tsx +++ b/src/ui/components/Header/Header.tsx @@ -1,46 +1,30 @@ -import { Box, Title, Space, Group, Button, SimpleGrid, Flex, Divider, Center } from "@mantine/core" +import { Title, Button, SimpleGrid, Flex, Box, Divider, Center } from "@mantine/core" import { useActivity } from "../../context/useActivity" import { Text } from "@mantine/core" export const Header = () => { - + const { getActivityText, isDoingActivity, endActivity, verifyExercise } = useActivity() - return + return GitMastery - - {isDoingActivity && + + {isDoingActivity &&
- - +
- {getActivityText()}
- - +
-
} -
- +
- - -} \ No newline at end of file +} diff --git a/src/ui/components/Navigation/ExerciseList.tsx b/src/ui/components/Navigation/ExerciseList.tsx index b2ee559..f594303 100644 --- a/src/ui/components/Navigation/ExerciseList.tsx +++ b/src/ui/components/Navigation/ExerciseList.tsx @@ -1,4 +1,4 @@ -import { ActionIcon, Autocomplete, Box, Button, Flex, Modal, Select, Stack, Text } from "@mantine/core" +import { ActionIcon, Box, Button, Flex, Select, Stack, Text } from "@mantine/core" import { IconCheck, IconPlus, IconX } from "@tabler/icons-react" import { buildExerciseUrl, buildLessonUrl, useWebContentsView } from "../../context/useWebContentsView" import { useExercises } from "../../hooks/query/useExercises"; @@ -236,24 +236,19 @@ export const ExerciseList = () => { return <> - - - + + Lessons - + {downloadedExercises?.map(exerciseData => ( ))} - - - - {/* @@ -279,57 +274,24 @@ export const DownloadedExercise = ({ exercise, status }: { exercise: Exercise, s const { navigate } = useWebContentsView(); const { startExercise } = useActivity(); - return + return {statusMap[status as keyof typeof statusMap]()} { navigate(buildExerciseUrl(exercise)); startExercise(exercise); - }} /> - -} - - - -const InProgress = () => { - return - - + } -const Correct = () => { - return - -} - -const Incorrect = () => { - return - -} +const StatusDot = ({ color }: { color: string }) => ( + +) -const statusMap = { - "correct": Correct, - "incorrect": Incorrect, - "in-progress": InProgress, - "not-started": InProgress, +const statusMap: Record ReturnType> = { + "correct": () => , + "incorrect": () => , + "in-progress": () => , + "not-started": () => , } \ No newline at end of file diff --git a/src/ui/components/Navigation/LeftBarWrapper.tsx b/src/ui/components/Navigation/LeftBarWrapper.tsx index a6c8c20..efb0f45 100644 --- a/src/ui/components/Navigation/LeftBarWrapper.tsx +++ b/src/ui/components/Navigation/LeftBarWrapper.tsx @@ -1,7 +1,7 @@ -import { Avatar, Box, Button, Divider, Flex, Group, Menu, Stack, Text, UnstyledButton } from "@mantine/core" +import { Avatar, Box, Divider, Flex, Group, Menu, Stack, Text, UnstyledButton } from "@mantine/core" import { TourList } from "./TourList" import { ExerciseList } from "./ExerciseList" -import { IconArrowsLeftRight, IconChevronRight, IconMessageCircle, IconPhoto, IconSearch, IconSettings, IconTrash } from "@tabler/icons-react" +import { IconChevronRight, IconSettings } from "@tabler/icons-react" import { forwardRef } from "react" import { useLocalStorage } from "@mantine/hooks" @@ -11,30 +11,19 @@ export const LeftBarWrapper = () => { key: 'onboarding-completed', defaultValue: false, }) - return + return {/* Tours */} - - + - {/* Lessons (scrollable) */} - - - - - {/* User profile (fixed)*/} - - + { } onClick={() => setOnboardingCompleted(false)}> Setup GitMastery - {/* } onClick={selectExePath}> - Set .exe path (Windows) - */} - {/* } onClick={selectSaveDir}> - Configure save location - - } onClick={setupGitMastery}> - Setup Git Mastery - */} - - {/* - - Danger zone - - } - > - Reset progress - */} - } + interface UserButtonProps extends React.ComponentPropsWithoutRef<'button'> { image: string; name: string; email: string; icon?: React.ReactNode; } + const UserButton = forwardRef( ({ image, name, email, icon, ...others }: UserButtonProps, ref) => ( - -
+ {name} - {email} -
- +
{icon || } diff --git a/src/ui/components/Navigation/TourList.module.css b/src/ui/components/Navigation/TourList.module.css deleted file mode 100644 index ec60845..0000000 --- a/src/ui/components/Navigation/TourList.module.css +++ /dev/null @@ -1,3 +0,0 @@ -.icon { - transition: all 0.15s ease-in-out; -} \ No newline at end of file diff --git a/src/ui/components/Navigation/TourList.tsx b/src/ui/components/Navigation/TourList.tsx index ce034ca..5bc0c5f 100644 --- a/src/ui/components/Navigation/TourList.tsx +++ b/src/ui/components/Navigation/TourList.tsx @@ -3,15 +3,13 @@ import { useDisclosure } from "@mantine/hooks" import type { Lesson, Tour, TourData } from "../../../types/Tour" import { useCustomQuery } from "../../hooks/query/useCustomQuery" import { buildLessonUrl, useWebContentsView } from "../../context/useWebContentsView" -import { IconChevronCompactDown, IconChevronDown } from "@tabler/icons-react" - -import classes from './TourList.module.css' +import { IconChevronDown } from "@tabler/icons-react" import { NavigationButton } from "./NavigationButton/NavigationButton" export const TourList = () => { const { data: tourList, isLoading } = useCustomQuery({ queryKey: ["tour_list"], queryUrl: "https://git-mastery.org/lessons/lessons.json" }) - return + return Tours {tourList ? Object.values(tourList).map((tour, index) => ) : "No data"} @@ -21,46 +19,33 @@ const TourItem = ({ tour, index }: { tour: Tour, index: number }) => { const [opened, { toggle }] = useDisclosure(false); const { navigate } = useWebContentsView(); - return + return - - - + + {buildLesson({ path: `lessons/trail/${tour.folder}`, title: "Tour Home" }, navigate)} {Object.values(tour.lessons).map(lesson => buildLesson(lesson, navigate))} - + } const buildLesson = (lesson: Lesson, navigate: (url: string) => void) => { return navigate(buildLessonUrl(lesson))} /> -} \ No newline at end of file +} diff --git a/src/ui/components/Terminal/Terminal.tsx b/src/ui/components/Terminal/Terminal.tsx index fba5db1..922fd8a 100644 --- a/src/ui/components/Terminal/Terminal.tsx +++ b/src/ui/components/Terminal/Terminal.tsx @@ -42,7 +42,7 @@ const XTermComponent = () => { return (
); }; diff --git a/src/ui/components/Website/WebsiteWrapper.tsx b/src/ui/components/Website/WebsiteWrapper.tsx index a1e8e8d..41101ac 100644 --- a/src/ui/components/Website/WebsiteWrapper.tsx +++ b/src/ui/components/Website/WebsiteWrapper.tsx @@ -1,4 +1,4 @@ -import { Alert, Badge, Box, Breadcrumbs, Center, Flex, Image, Text } from "@mantine/core" +import { Alert, Badge, Box, Breadcrumbs, Flex, Image, Text } from "@mantine/core" import { useEffect, useRef } from "react" import { useWebContentsView } from "../../context/useWebContentsView" import { formatBreadcrumb } from "../../utils/format" @@ -66,23 +66,20 @@ export const WebsiteWrapper = () => { - return + return - {/* Map all except last one */} {breadcrumbs.slice(0, -1).map((breadcrumb, index) => ( {formatBreadcrumb(breadcrumb).toUpperCase()} ))} - {breadcrumbs.length > 0 ? {formatBreadcrumb(breadcrumbs[breadcrumbs.length - 1])} : <>} - {currentUrl ? <> : } title="Get started with lessons or exercises"> + {currentUrl ? <> : } title="Get started with lessons or exercises"> Choose a tour from the left sidebar, or download an exercise and start doing it! } - } \ No newline at end of file diff --git a/src/ui/index.css b/src/ui/index.css deleted file mode 100644 index b082a28..0000000 --- a/src/ui/index.css +++ /dev/null @@ -1,13 +0,0 @@ -/* ─── Typography ─────────────────────────────────────────── */ -:root { - --font-heading: 'Noto Serif', Georgia, serif; - --font-body: 'Inter', system-ui, sans-serif; -} - -body { - font-family: var(--font-body); -} - -h1, h2, h3, h4, h5, h6 { - font-family: var(--font-heading); -} diff --git a/src/ui/main.tsx b/src/ui/main.tsx index 0d5999d..e3a88dc 100644 --- a/src/ui/main.tsx +++ b/src/ui/main.tsx @@ -2,6 +2,7 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import '@mantine/core/styles.css'; import '@mantine/notifications/styles.css'; +import './tailwind.css'; import App from './App.tsx' import { colorsTuple, createTheme, MantineProvider, Text } from '@mantine/core' import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; diff --git a/src/ui/pages/Onboarding.tsx b/src/ui/pages/Onboarding.tsx index e93788a..d1a8892 100644 --- a/src/ui/pages/Onboarding.tsx +++ b/src/ui/pages/Onboarding.tsx @@ -1,12 +1,11 @@ import { useEffect, useState } from "react" import { useWebContentsView } from "../context/useWebContentsView" -import { Accordion, Alert, Box, Button, Center, Container, Flex, Group, Image, Stack, Stepper, Text, Timeline, Title, Tooltip } from "@mantine/core"; +import { Accordion, Alert, Box, Button, Center, Flex, Group, Image, Stack, Stepper, Text, Title } from "@mantine/core"; import logo from "../assets/logo.png" -import { IconAlertCircle, IconCheck, IconCheckFilled, IconCircleCheck, IconCircleX, IconCross, IconExternalLink, IconFolder, IconGitBranch, IconGitCommit, IconGitPullRequest, IconMessageDots, IconX } from "@tabler/icons-react"; +import { IconAlertCircle, IconCheck, IconCircleCheck, IconCircleX, IconExternalLink, IconFolder, IconGitBranch, IconX } from "@tabler/icons-react"; import { useElectronStream } from "../hooks/useElectronStream"; import { notifications } from "@mantine/notifications"; -import { useGitMasteryTask } from "../contexts/GitMasteryTaskContext"; const selectSaveDir = async () => { const path = await window.electron.selectFolder(); @@ -50,24 +49,8 @@ export const Onboarding = ({ onCompleteOnboarding }: { onCompleteOnboarding: () } } - return - + return + {active != 0 && @@ -113,19 +94,10 @@ export const Onboarding = ({ onCompleteOnboarding }: { onCompleteOnboarding: () const Step0 = () => { return - - - + Git Mastery Logo - - - - Welcome to GitMastery! GitMastery is an open-source tool for anyone looking to upgrade their mastery of Git. @@ -134,7 +106,6 @@ const Step0 = () => { - } const Step1 = ({ setCanGoNext }: { @@ -156,21 +127,16 @@ const Step1 = ({ setCanGoNext }: { GitMastery needs to know where to save your in-progress exercises. These exercises are stored as folders on your hard drive. - - - - + {saveLoc} - - } @@ -294,14 +260,10 @@ const Step2 = ({ To fully understand Git, you must have Git on your local machine. GitMastery uses Git behind-the-hood to run all the lessons and exercises. - - - Install GitHub CLI @@ -309,24 +271,17 @@ const Step2 = ({ This tool lets GitMastery sync your progress to your GitHub account. - - - - - + }>Installation help - + - - - } @@ -512,16 +467,11 @@ const Step3 = ({ Download Git Parser {statusComponent} - {/* {gitMasteryInstalled ? : } */} - This is a custom in-house command line tool that GitMastery uses to check the correctness of your answers. - - - Setup Git Mastery @@ -529,31 +479,23 @@ const Step3 = ({ Configure your system for GitMastery. - - {/* */} - - - - + }>Installation help - + - - - } const Step4 = () => { - return - {/* Setup complete */} + return
- }> + }> You are now ready to use GitMastery! -
+ +
} diff --git a/src/ui/tailwind.css b/src/ui/tailwind.css new file mode 100644 index 0000000..7bf2e07 --- /dev/null +++ b/src/ui/tailwind.css @@ -0,0 +1,7 @@ +@import "tailwindcss"; + +@theme { + --color-gm-green: #2D864E; + --color-gm-bone: #F8F8F8; + --color-gm-dark-green: #717c4d; +} diff --git a/vite.config.ts b/vite.config.ts index 5015239..8fcbbc9 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,9 +1,9 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' -// https://vite.dev/config/ export default defineConfig({ - plugins: [react()], + plugins: [tailwindcss(), react()], base: "./", build: { outDir: "dist-react"