diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..9030888 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,5 @@ +{ + "enabledPlugins": { + "frontend-design@claude-plugins-official": true + } +} diff --git a/.claude/settings.local.json b/.claude/settings.local.json index c4632e7..0e6cbdf 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -4,7 +4,21 @@ "Bash(cargo build *)", "Bash(npm run *)", "Bash(kill %1)", - "Bash(perl -0pi -e 's/\\\\{line \\\\|\\\\| \" \"\\\\}/{displayLine\\(line\\) || \" \"}/g' src/App.svelte)" + "Bash(perl -0pi -e 's/\\\\{line \\\\|\\\\| \" \"\\\\}/{displayLine\\(line\\) || \" \"}/g' src/App.svelte)", + "Bash(kill 26306)", + "Bash(convert --version)", + "Bash(magick /mnt/data/Development/GitLite/src-tauri/icons/icon.ico /mnt/data/Development/GitLite/src-tauri/icons/icon.png)", + "Bash(magick /mnt/data/Development/GitLite/src-tauri/icons/icon.ico -type TrueColorAlpha -alpha on PNG32:/mnt/data/Development/GitLite/src-tauri/icons/icon.png)", + "Bash(magick identify *)", + "Bash(magick -size 512x512 xc:\"rgba\\(70,130,180,255\\)\" PNG32:/mnt/data/Development/GitLite/src-tauri/icons/icon.png)", + "Bash(pkill -f \"vite --host\")", + "Bash(pkill -f \"tauri dev\")", + "Bash(pkill -f \"tauri_git_lite\")", + "Bash(xargs kill -9)", + "Bash(grep -qE \"\\(Running \\\\`target|error\\\\[|panicked|terminated\\)\" /tmp/claude-1000/-mnt-data-Development-GitLite/71a8b49f-ac61-4ad9-aaba-dc0219044038/tasks/b4ujhgmdk.output)", + "Bash(grep -qE \"\\(Running \\\\`target|error\\\\[|panicked|terminated\\)\" /tmp/claude-1000/-mnt-data-Development-GitLite/71a8b49f-ac61-4ad9-aaba-dc0219044038/tasks/bt54rikhh.output)", + "Bash(grep -qE \"\\(Running \\\\`target|error\\\\[|panicked|terminated\\)\" /tmp/claude-1000/-mnt-data-Development-GitLite/71a8b49f-ac61-4ad9-aaba-dc0219044038/tasks/b7nyub68s.output)", + "Bash(npm install *)" ] } } diff --git a/.gitignore b/.gitignore index 962d542..ab694d8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ /dist /src-tauri/target *.log +.idea .DS_Store diff --git a/package-lock.json b/package-lock.json index 43c88bd..a637b9a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,10 @@ "version": "0.1.0", "dependencies": { "@lucide/svelte": "^1.21.0", + "@tailwindcss/vite": "^4.3.1", "@tauri-apps/api": "^2.5.0", - "svelte": "^5.0.0" + "svelte": "^5.0.0", + "tailwindcss": "^4.3.1" }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^5.0.0", @@ -27,7 +29,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -44,7 +45,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -61,7 +61,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -78,7 +77,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -95,7 +93,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -112,7 +109,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -129,7 +125,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -146,7 +141,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -163,7 +157,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -180,7 +173,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -197,7 +189,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -214,7 +205,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -231,7 +221,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -248,7 +237,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -265,7 +253,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -282,7 +269,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -299,7 +285,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -316,7 +301,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -333,7 +317,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -350,7 +333,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -367,7 +349,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -384,7 +365,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -401,7 +381,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -418,7 +397,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -435,7 +413,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -452,7 +429,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -523,7 +499,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -537,7 +512,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -551,7 +525,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -565,7 +538,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -579,7 +551,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -593,7 +564,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -607,7 +577,6 @@ "cpu": [ "arm" ], - "dev": true, "libc": [ "glibc" ], @@ -624,7 +593,6 @@ "cpu": [ "arm" ], - "dev": true, "libc": [ "musl" ], @@ -641,7 +609,6 @@ "cpu": [ "arm64" ], - "dev": true, "libc": [ "glibc" ], @@ -658,7 +625,6 @@ "cpu": [ "arm64" ], - "dev": true, "libc": [ "musl" ], @@ -675,7 +641,6 @@ "cpu": [ "loong64" ], - "dev": true, "libc": [ "glibc" ], @@ -692,7 +657,6 @@ "cpu": [ "loong64" ], - "dev": true, "libc": [ "musl" ], @@ -709,7 +673,6 @@ "cpu": [ "ppc64" ], - "dev": true, "libc": [ "glibc" ], @@ -726,7 +689,6 @@ "cpu": [ "ppc64" ], - "dev": true, "libc": [ "musl" ], @@ -743,7 +705,6 @@ "cpu": [ "riscv64" ], - "dev": true, "libc": [ "glibc" ], @@ -760,7 +721,6 @@ "cpu": [ "riscv64" ], - "dev": true, "libc": [ "musl" ], @@ -777,7 +737,6 @@ "cpu": [ "s390x" ], - "dev": true, "libc": [ "glibc" ], @@ -794,7 +753,6 @@ "cpu": [ "x64" ], - "dev": true, "libc": [ "glibc" ], @@ -811,7 +769,6 @@ "cpu": [ "x64" ], - "dev": true, "libc": [ "musl" ], @@ -828,7 +785,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -842,7 +798,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -856,7 +811,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -870,7 +824,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -884,7 +837,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -898,7 +850,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -964,6 +915,275 @@ "vite": "^6.0.0" } }, + "node_modules/@tailwindcss/node": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.1.tgz", + "integrity": "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "5.21.6", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.1" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.1.tgz", + "integrity": "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.1", + "@tailwindcss/oxide-darwin-arm64": "4.3.1", + "@tailwindcss/oxide-darwin-x64": "4.3.1", + "@tailwindcss/oxide-freebsd-x64": "4.3.1", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.1", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.1", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.1", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.1", + "@tailwindcss/oxide-linux-x64-musl": "4.3.1", + "@tailwindcss/oxide-wasm32-wasi": "4.3.1", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.1", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.1" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.1.tgz", + "integrity": "sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.1.tgz", + "integrity": "sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.1.tgz", + "integrity": "sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.1.tgz", + "integrity": "sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.1.tgz", + "integrity": "sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.1.tgz", + "integrity": "sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.1.tgz", + "integrity": "sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.1.tgz", + "integrity": "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.1.tgz", + "integrity": "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.1.tgz", + "integrity": "sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "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.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.1.tgz", + "integrity": "sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.1.tgz", + "integrity": "sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.1.tgz", + "integrity": "sha512-hItDHuIIlEV61R+faXu66s1K36aTurO/Qw0e45Vskz57gXl9pWOT6eg3zmcEui6CZXddbN7zd41bwmvag4JGwQ==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.3.1", + "@tailwindcss/oxide": "4.3.1", + "tailwindcss": "4.3.1" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7 || ^8" + } + }, "node_modules/@tauri-apps/api": { "version": "2.11.1", "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.11.1.tgz", @@ -1301,17 +1521,38 @@ "node": ">=0.10.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==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/devalue": { "version": "5.8.1", "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.8.1.tgz", "integrity": "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==", "license": "MIT" }, + "node_modules/enhanced-resolve": { + "version": "5.21.6", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", + "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/esbuild": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -1376,7 +1617,6 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -1394,7 +1634,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -1405,6 +1644,12 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, "node_modules/is-reference": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", @@ -1414,6 +1659,15 @@ "@types/estree": "^1.0.6" } }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/kleur": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", @@ -1424,6 +1678,267 @@ "node": ">=6" } }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "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" + ], + "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" + ], + "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" + ], + "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" + ], + "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" + ], + "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" + ], + "libc": [ + "glibc" + ], + "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" + ], + "libc": [ + "musl" + ], + "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" + ], + "libc": [ + "glibc" + ], + "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" + ], + "libc": [ + "musl" + ], + "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" + ], + "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" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/locate-character": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", @@ -1460,7 +1975,6 @@ "version": "3.3.15", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", - "dev": true, "funding": [ { "type": "github", @@ -1479,14 +1993,12 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -1499,7 +2011,6 @@ "version": "8.5.15", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", - "dev": true, "funding": [ { "type": "opencollective", @@ -1542,7 +2053,6 @@ "version": "4.62.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", - "dev": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.9" @@ -1600,7 +2110,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -1658,11 +2167,29 @@ "typescript": ">=5.0.0" } }, + "node_modules/tailwindcss": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.1.tgz", + "integrity": "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==", + "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==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -1693,7 +2220,6 @@ "version": "6.4.3", "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", - "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", diff --git a/package.json b/package.json index dfb8ae5..a882301 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,10 @@ }, "dependencies": { "@lucide/svelte": "^1.21.0", + "@tailwindcss/vite": "^4.3.1", "@tauri-apps/api": "^2.5.0", - "svelte": "^5.0.0" + "svelte": "^5.0.0", + "tailwindcss": "^4.3.1" }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^5.0.0", diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index da38260..b7efc2c 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -3,5 +3,13 @@ "identifier": "default", "description": "Default permissions for the desktop window", "windows": ["main"], - "permissions": ["core:default"] + "permissions": [ + "core:default", + "core:window:allow-minimize", + "core:window:allow-toggle-maximize", + "core:window:allow-unminimize", + "core:window:allow-close", + "core:window:allow-is-maximized", + "core:window:allow-start-dragging" + ] } diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png new file mode 100644 index 0000000..3d0c8fe Binary files /dev/null and b/src-tauri/icons/icon.png differ diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 834aa7f..cb23cc4 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -13,11 +13,13 @@ "windows": [ { "label": "main", - "title": "Tauri Git Lite", + "title": "GitLite", "width": 1200, "height": 800, "minWidth": 900, - "minHeight": 600 + "minHeight": 600, + "decorations": false, + "shadow": true } ], "security": { diff --git a/src/App.svelte b/src/App.svelte index b7e4dc4..1b7ab7a 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -1,27 +1,17 @@ - Tauri Git Lite + GitLite + +
-
-
- - - -
+ -
- - - - -
-
+
- {#if errorMessage} - - {/if} - - {#if operation && operation !== "Opening repository"} -
-
- {/if} - - {#if hasConflicts} - - {/if} - -
- - -
-
-
- Current repo -

{status?.current_branch ?? "No repository"}

-

{activeRepoPath || "Enter a path and open a repository."}

-
- -
- {status?.upstream ?? "No upstream"} - {status?.ahead ?? 0} ahead - {status?.behind ?? 0} behind -
-
- -
-
-
-
- Working tree -

Status

-
-
- {stagedCount} staged - {unstagedCount} unstaged -
-
- - {#if !hasRepository} -
No repository loaded.
- {:else if status?.clean} -
Working tree is clean.
- {:else if changedFiles.length === 0} -
No file changes returned.
+ +
+
+ + + - - {:else} - No staged change - {/if} -
-
- -
- Unstaged - {statusLabel(file.unstaged)} -
- {#if file.unstaged} - - - {:else} - No unstaged change - {/if} -
-
- - - {/each} - +
- + +{#if compareDialogOpen && comparison} + { compareDialogOpen = false; }} + onSelectFile={selectDiffFile} + /> +{/if} + + +{#if resolveDialogOpen} + { resolveDialogOpen = false; }} + onSelectFile={selectConflictFile} + onMarkResolved={handleMarkResolved} + onApply={applyPreparedResolutions} + /> +{/if} diff --git a/src/app.css b/src/app.css index 0c7093e..e783cd0 100644 --- a/src/app.css +++ b/src/app.css @@ -1,1575 +1,794 @@ -:root { - color: #202326; - background: #eef1f3; - font-family: - Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -* { - box-sizing: border-box; -} - -html, -body, -#app { - width: 100%; - height: 100%; - margin: 0; -} - -body { - overflow: hidden; -} - -button, -input, -textarea { - font: inherit; -} - -button { - display: inline-flex; - align-items: center; - justify-content: center; - gap: 7px; - min-height: 32px; - padding: 0 12px; - border: 1px solid #c7ced4; - border-radius: 6px; - color: #202326; - background: #ffffff; - cursor: pointer; - transition: - background 140ms ease, - border-color 140ms ease, - color 140ms ease; -} - -button:hover:not(:disabled) { - border-color: #8fa0ad; - background: #f6f8f9; -} - -button:disabled { - cursor: not-allowed; - opacity: 0.55; -} - -input, -textarea { - width: 100%; - border: 1px solid #c7ced4; - border-radius: 6px; - color: #202326; - background: #ffffff; - outline: none; -} - -input:focus, -textarea:focus { - border-color: #2f7da1; - box-shadow: 0 0 0 3px rgba(47, 125, 161, 0.14); -} - -input { - height: 34px; - padding: 0 11px; -} - -textarea { - resize: vertical; - min-height: 132px; - padding: 10px 11px; - line-height: 1.45; -} - -.shell { - display: grid; - grid-template-rows: auto auto 1fr; - height: 100%; - padding: 12px; - gap: 10px; -} - -.topbar { - display: grid; - grid-template-columns: minmax(0, 1fr) auto; - align-items: end; - gap: 12px; - min-height: 54px; - padding: 10px; - border: 1px solid #d2d8de; - border-radius: 8px; - background: #fbfcfd; -} - -.repo-form { - display: grid; - grid-template-columns: auto minmax(280px, 1fr) auto; - align-items: center; - gap: 9px; -} - -.repo-form label { - color: #54606a; - font-size: 12px; - font-weight: 700; - text-transform: uppercase; -} - -.toolbar { - display: flex; - align-items: center; - gap: 8px; -} - -.auto-refresh-toggle.active { - border-color: #2f8f6a; - color: #1b6e4f; - background: #e6f6ee; -} - -.auto-refresh-toggle.active:hover:not(:disabled) { - border-color: #25785a; - background: #d8f0e3; -} - -.primary-button { - border-color: #256f8f; - color: #ffffff; - background: #256f8f; -} - -.primary-button:hover:not(:disabled) { - border-color: #1f5f7b; - background: #1f5f7b; -} - -.notice { - display: flex; - align-items: center; - gap: 8px; - min-height: 36px; - padding: 8px 11px; - border: 1px solid; - border-radius: 8px; - font-size: 13px; -} - -.notice.error { - border-color: #e8aaa4; - color: #8e2d27; - background: #fff4f2; -} - -.notice.busy { - border-color: #a7cfe2; - color: #245d78; - background: #edf8fd; -} - -.notice.conflict { - border-color: #e3b778; - color: #8a4c0e; - background: #fff6e7; -} - -.notice.conflict button { - margin-left: auto; - min-height: 30px; - padding: 0 12px; - border-color: #e3b778; - color: #8a4c0e; - background: #ffffff; - font-size: 13px; - font-weight: 700; -} - -.workspace { - display: grid; - grid-template-columns: 320px minmax(0, 1fr) 440px; - min-height: 0; - gap: 10px; -} - -.history-aside { - display: grid; - min-height: 0; -} - -.left-sidebar { - display: grid; - grid-template-rows: minmax(220px, 0.9fr) minmax(260px, 1.1fr); - min-height: 0; - gap: 10px; -} - -.branches, -.explorer-panel, -.main-panel, -.status-panel, -.commit-panel, -.file-history-panel, -.history-panel, -.compare-panel { - min-height: 0; - border: 1px solid #d2d8de; - border-radius: 8px; - background: #fbfcfd; -} - -.branches, -.explorer-panel { - display: grid; - grid-template-rows: auto 1fr; - overflow: hidden; -} - -.section-heading { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; - min-height: 58px; - padding: 12px; - border-bottom: 1px solid #dce1e5; -} - -.section-heading h2, -.repo-summary h1 { - margin: 1px 0 0; - color: #202326; -} - -.section-heading h2 { - font-size: 16px; - line-height: 1.2; -} - -.repo-summary h1 { - font-size: 24px; - line-height: 1.15; -} - -.eyebrow { - color: #697681; - font-size: 11px; - font-weight: 800; - letter-spacing: 0; - text-transform: uppercase; -} - -.counter, -.active-pill, -.status-counts span, -.sync-stats strong, -.sync-stats span { - display: inline-flex; - align-items: center; - min-height: 24px; - padding: 0 8px; - border-radius: 999px; - font-size: 12px; - font-weight: 700; - white-space: nowrap; -} - -.counter, -.status-counts span, -.sync-stats span { - color: #4f5d66; - background: #edf0f2; -} - -.active-pill { - color: #176239; - background: #e4f4ea; -} - -.branch-list, -.explorer-list, -.file-list, -.history-list { - overflow: auto; -} - -.branch-list, -.explorer-list { - padding: 8px; -} - -.branch-group-label { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; - margin: 2px 2px 6px; - color: #697681; - font-size: 11px; - font-weight: 800; - letter-spacing: 0.04em; - text-transform: uppercase; -} - -.branch-group-label:not(:first-child) { - margin-top: 12px; -} - -.branch-group-count { - display: inline-flex; - align-items: center; - min-height: 18px; - padding: 0 7px; - border-radius: 999px; - color: #4f5d66; - background: #edf0f2; - font-size: 11px; -} - -.branch-row { - display: grid; - grid-template-columns: minmax(0, 1fr) auto; - align-items: center; - gap: 8px; - min-height: 48px; - padding: 8px; - border: 1px solid transparent; - border-radius: 8px; -} - -.branch-row + .branch-row { - margin-top: 4px; -} - -.branch-row.current { - border-color: #b9ddc6; - background: #f0f8f3; -} - -.branch-info { - display: flex; - align-items: center; - min-width: 0; - gap: 8px; -} - -.branch-info div { - min-width: 0; -} - -.branch-info strong, -.file-title strong { - display: block; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.branch-info strong { - font-size: 13px; -} - -.branch-info span { - display: block; - margin-top: 2px; - color: #697681; - font-size: 12px; -} - -.branch-actions { - display: flex; - align-items: center; - justify-content: flex-end; - gap: 6px; -} - -.branch-actions button { - min-height: 28px; - padding: 0 8px; - font-size: 12px; -} - -.explorer-row { - display: grid; - grid-template-columns: auto auto minmax(0, 1fr) auto; - align-items: center; - gap: 7px; - justify-content: stretch; - width: 100%; - min-height: 34px; - padding: 5px 8px 5px calc(8px + var(--depth, 0) * 14px); - border: 1px solid #c7ced4; - border-radius: 6px; - background: #ffffff; - text-align: left; - transition: - background 140ms ease, - border-color 140ms ease; -} - -.explorer-row + .explorer-row { - margin-top: 4px; -} - -.explorer-row:hover { - border-color: #8fa0ad; - background: #f6f8f9; -} - -.explorer-row.active { - border-color: #9fc8dc; - background: #edf8fd; -} - -.explorer-row.folder { - font-weight: 800; -} - -.explorer-row svg { - color: #4f7d96; -} - -.tree-toggle, -.explorer-select { - min-height: 22px; - padding: 0; - border: 0; - background: transparent; -} - -.tree-toggle { - width: 14px; -} - -.tree-toggle:hover:not(:disabled), -.explorer-select:hover:not(:disabled) { - background: transparent; -} - -.explorer-select { - justify-content: flex-start; - min-width: 0; -} - -.tree-spacer { - width: 14px; -} - -.explorer-select span { - overflow: hidden; - font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; - font-size: 12px; - font-weight: 700; - text-overflow: ellipsis; - white-space: nowrap; -} - -.main-panel { - display: grid; - grid-template-rows: auto minmax(0, 1fr) auto; - overflow: auto; -} - -.repo-summary { - display: grid; - grid-template-columns: minmax(0, 1fr) auto; - gap: 12px; - padding: 16px; - border-bottom: 1px solid #dce1e5; -} - -.repo-summary p { - overflow: hidden; - margin: 5px 0 0; - color: #5f6b75; - font-size: 13px; - text-overflow: ellipsis; - white-space: nowrap; -} - -.sync-stats, -.status-counts { - display: flex; - align-items: center; - gap: 6px; - flex-wrap: wrap; - justify-content: flex-end; -} - -.sync-stats strong:first-of-type { - color: #8a4c0e; - background: #fff2d7; -} - -.sync-stats strong:last-of-type { - color: #255b8b; - background: #e7f1fb; -} - -.status-grid { - display: grid; - grid-template-columns: minmax(0, 1fr) 360px; - min-height: 0; - gap: 10px; - padding: 10px; -} - -.status-panel, -.commit-panel, -.file-history-panel, -.history-panel { - display: grid; - grid-template-rows: auto 1fr; - overflow: hidden; -} - -.side-stack { - display: grid; - grid-template-rows: auto minmax(0, 1fr); - min-height: 0; - gap: 10px; -} - -.file-list { - padding: 8px; -} - -.file-row { - display: grid; - gap: 8px; - padding: 10px; - border: 1px solid #dce1e5; - border-radius: 8px; - background: #ffffff; -} - -.file-row + .file-row { - margin-top: 8px; -} - -.file-title strong { - font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; - font-size: 13px; -} - -.change-lanes { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 8px; -} - -.change-lane { - display: grid; - grid-template-columns: auto auto minmax(0, 1fr); - align-items: center; - gap: 8px; - min-height: 40px; - padding: 7px; - border: 1px solid #dce1e5; - border-radius: 6px; - background: #f7f9fa; -} - -.change-lane.inactive { - color: #8a949c; - background: #fafafa; -} - -.lane-name { - color: #596670; - font-size: 12px; - font-weight: 800; -} - -.lane-actions { - display: flex; - align-items: center; - justify-content: flex-end; - min-width: 0; - gap: 6px; -} - -.lane-actions button { - min-height: 28px; - padding: 0 8px; - font-size: 12px; -} - -.quiet { - overflow: hidden; - color: #7d8891; - font-size: 12px; - text-overflow: ellipsis; - white-space: nowrap; -} - -.status-badge { - min-width: 74px; - padding: 3px 7px; - border-radius: 999px; - font-size: 11px; - font-weight: 800; - text-align: center; - text-transform: uppercase; - white-space: nowrap; -} - -.status-badge.modified { - color: #7b4a05; - background: #ffe8bb; -} - -.status-badge.added, -.status-badge.untracked { - color: #176239; - background: #dff3e7; -} - -.status-badge.deleted { - color: #9b2e29; - background: #ffe1df; -} - -.status-badge.renamed { - color: #255b8b; - background: #e0effd; -} - -.status-badge.conflicted { - color: #8f2d61; - background: #fde2f0; -} - -.status-badge.unknown, -.status-badge.none { - color: #596670; - background: #e9edef; -} - -.commit-panel { - align-content: start; -} - -.commit-form { - display: grid; - align-content: start; - gap: 10px; - padding: 12px; -} - -.commit-form .primary-button { - width: 100%; -} - -.commit-hint { - display: flex; - align-items: center; - gap: 8px; - margin: 0 12px 12px; - padding: 10px; - border: 1px solid #dce1e5; - border-radius: 8px; - color: #596670; - background: #f7f9fa; - font-size: 13px; -} - -.commit-hint strong { - color: #202326; - font-size: 20px; -} - -.history-list { - padding: 8px; -} - -.commit-row { - display: grid; - gap: 8px; - padding: 10px; - border: 1px solid #dce1e5; - border-radius: 8px; - background: #ffffff; -} - -.commit-row + .commit-row { - margin-top: 8px; -} - -.commit-row.compact { - padding: 9px; -} - -.commit-line { - display: flex; - align-items: flex-start; - min-width: 0; - gap: 8px; -} - -.commit-line svg { - flex: 0 0 auto; - margin-top: 2px; - color: #4f7d96; -} - -.commit-line div { - min-width: 0; -} - -.commit-line strong { - display: block; - overflow: hidden; - color: #202326; - font-size: 13px; - line-height: 1.3; - text-overflow: ellipsis; - white-space: nowrap; -} - -.commit-line span { - display: block; - overflow: hidden; - margin-top: 3px; - color: #697681; - font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; - font-size: 11px; - text-overflow: ellipsis; - white-space: nowrap; -} - -.ref-list { - display: flex; - flex-wrap: wrap; - gap: 5px; -} - -.ref-list span { - max-width: 100%; - overflow: hidden; - padding: 3px 7px; - border-radius: 999px; - color: #255b8b; - background: #e7f1fb; - font-size: 11px; - font-weight: 800; - text-overflow: ellipsis; - white-space: nowrap; -} - -.commit-files { - display: grid; - gap: 6px; -} - -.commit-files-toggle { - justify-content: flex-start; - gap: 5px; - min-height: 26px; - padding: 0 8px; - border-color: transparent; - background: transparent; - color: #4f5d66; - font-size: 12px; - font-weight: 700; -} - -.commit-files-toggle:hover:not(:disabled) { - border-color: #c7ced4; - background: #f6f8f9; -} - -.commit-file-list { - display: grid; - gap: 5px; -} - -.commit-file-button { - display: grid; - grid-template-columns: auto minmax(0, 1fr); - justify-content: stretch; - width: 100%; - min-height: 30px; - padding: 5px 7px; - text-align: left; -} - -.commit-file-button strong { - overflow: hidden; - color: #202326; - font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; - font-size: 12px; - font-weight: 700; - text-overflow: ellipsis; - white-space: nowrap; -} - -.commit-actions { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; -} - -.commit-actions time { - overflow: hidden; - color: #6c7882; - font-size: 12px; - text-overflow: ellipsis; - white-space: nowrap; -} - -.commit-actions button { - min-height: 28px; - padding: 0 8px; - font-size: 12px; -} - -.commit-action-buttons { - display: flex; - align-items: center; - gap: 6px; -} - -.graph-list { - padding: 0; -} - -.graph-row { - display: grid; - grid-template-columns: auto minmax(0, 1fr); - gap: 0; - margin: 0; - padding: 0; - border: none; - border-radius: 0; - background: none; -} - -.graph-row + .graph-row { - margin-top: 0; -} - -.graph-gutter { - position: relative; - align-self: stretch; - min-height: 100%; - background: #fdfdfe; -} - -.graph-svg { - position: absolute; - inset: 0; - width: 100%; - height: 100%; - overflow: visible; -} - -.graph-dot { - position: absolute; - top: 50%; - width: 11px; - height: 11px; - border-radius: 999px; - background: var(--dot-color, #2f6fb0); - border: 2px solid #ffffff; - box-shadow: 0 0 0 1px var(--dot-color, #2f6fb0); - transform: translate(-50%, -50%); -} - -.graph-dot.merge { - width: 13px; - height: 13px; - background: #ffffff; - border-color: var(--dot-color, #2f6fb0); - box-shadow: 0 0 0 1px var(--dot-color, #2f6fb0); -} - -.commit-body { - display: grid; - gap: 8px; - min-width: 0; - padding: 11px 12px; -} - -.graph-row + .graph-row .commit-body { - border-top: 1px solid #e7ebee; -} - -.graph-row:hover .commit-body { - background: #f6f9fb; -} - -.compare-panel { - display: grid; - grid-template-rows: auto auto; - margin: 0 10px 10px; -} - -.compare-form { - display: grid; - grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto; - align-items: end; - gap: 10px; - padding: 12px; - border-bottom: 1px solid #dce1e5; -} - -.compare-field { - display: grid; - gap: 5px; - min-width: 0; -} - -.compare-field span { - color: #596670; - font-size: 12px; - font-weight: 800; -} - -.compare-field select { - width: 100%; - min-height: 36px; - padding: 0 8px; - border: 1px solid #c4ccd3; - border-radius: 6px; - background: #ffffff; - color: #202326; - font-size: 13px; -} - -.compare-arrow { - margin-bottom: 8px; - color: #4f7d96; -} - -.compare-summary { - display: flex; - align-items: center; - justify-content: space-between; - flex-wrap: wrap; - gap: 10px; - padding: 12px; -} - -.compare-range { - display: flex; - align-items: center; - gap: 8px; - color: #4f7d96; -} - -.compare-range .hash { - padding: 3px 8px; - border-radius: 999px; - background: #e7f1fb; - color: #255b8b; - font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; - font-size: 12px; - font-weight: 700; -} - -.compare-count { - color: #596670; - font-size: 13px; - font-weight: 700; -} - -.dialog-backdrop { - position: fixed; - inset: 0; - z-index: 50; - display: grid; - place-items: center; - padding: 24px; - background: rgba(20, 26, 31, 0.45); -} - -.dialog { - display: grid; - grid-template-rows: auto minmax(0, 1fr); - width: min(1100px, 100%); - height: min(760px, 100%); - border: 1px solid #c4ccd3; - border-radius: 12px; - background: #fbfcfd; - box-shadow: 0 18px 48px rgba(20, 26, 31, 0.32); - overflow: hidden; -} - -.dialog-header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; - padding: 14px 16px; - border-bottom: 1px solid #dce1e5; -} - -.dialog-range { - display: flex; - align-items: center; - gap: 8px; - margin: 2px 0 0; - color: #4f7d96; - font-size: 16px; -} - -.dialog-range .hash { - padding: 3px 8px; - border-radius: 999px; - background: #e7f1fb; - color: #255b8b; - font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; - font-size: 13px; - font-weight: 700; -} - -.dialog-close { - min-height: 34px; - min-width: 34px; - padding: 0; - justify-content: center; -} - -.dialog-body { - display: grid; - grid-template-columns: 300px minmax(0, 1fr); - min-height: 0; -} - -.dialog-files { - display: grid; - align-content: start; - gap: 5px; - padding: 10px; - overflow: auto; - border-right: 1px solid #dce1e5; - background: #f4f6f8; -} - -.dialog-file-row { - display: grid; - grid-template-columns: auto minmax(0, 1fr) auto; - align-items: center; - gap: 8px; - padding: 7px 8px; - border: 1px solid #dce1e5; - border-radius: 6px; - background: #ffffff; - text-align: left; -} - -.dialog-file-row.active { - border-color: #9cc2e6; - background: #e7f1fb; -} - -.dialog-file-row strong { - overflow: hidden; - color: #202326; - font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; - font-size: 12px; - font-weight: 700; - text-overflow: ellipsis; - white-space: nowrap; -} - -.dialog-diff { - display: grid; - min-height: 0; - padding: 10px; -} - -.dialog-diff .diff-view { - max-height: none; -} - -.dialog-footer { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; - padding: 12px 16px; - border-top: 1px solid #dce1e5; - background: #f4f6f8; -} - -.dialog-footer-info { - color: #4f5d66; - font-size: 13px; - font-weight: 700; -} - -.dialog-file-row.prepared { - border-color: #b9ddc6; - background: #f0f8f3; -} - -.dialog-file-row.prepared.active { - border-color: #4aa777; - background: #e4f4ea; -} - -.dialog-file-row svg { - color: #1f7a4d; -} - -.prepared-tag { - display: inline-flex; - align-items: center; - gap: 4px; - margin-right: auto; - color: #1f7a4d; - font-size: 12px; - font-weight: 700; -} +@import "tailwindcss"; -.dialog-title { - margin: 2px 0 0; - color: #202326; - font-size: 16px; -} - -.resolve-editor { - display: flex; - flex-direction: column; - min-height: 0; - padding: 10px; - gap: 8px; -} - -.resolve-toolbar { - display: flex; - align-items: center; - flex-wrap: wrap; - gap: 8px; -} - -.resolve-toolbar button { - min-height: 32px; - padding: 0 10px; - font-size: 13px; -} +@theme { + --color-ink: #202326; + --color-ink-muted: #697681; + --color-ink-faint: #6c7882; + --color-ink-dim: #5f6b75; + --color-ink-quiet: #596670; -.resolve-toolbar-label { - color: #596670; - font-size: 12px; - font-weight: 800; -} - -.resolve-status { - display: inline-flex; - align-items: center; - gap: 5px; - margin-left: auto; - font-size: 12px; - font-weight: 700; - color: #8a4c0e; -} + --color-surface: #fbfcfd; + --color-surface-alt: #eef1f3; + --color-surface-dim: #f7f9fa; + --color-surface-hover: #f6f8f9; -.resolve-textarea { - width: 100%; - flex: 1 1 auto; - min-height: 120px; - padding: 10px; - border: 1px solid #c4ccd3; - border-radius: 6px; - background: #ffffff; - color: #202326; - font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; - font-size: 12px; - line-height: 1.5; - tab-size: 2; - resize: none; - white-space: pre; -} + --color-border: #d2d8de; + --color-border-subtle: #dce1e5; + --color-border-input: #c7ced4; -.resolve-structured { - display: grid; - align-content: start; - gap: 8px; - flex: 1 1 auto; - min-height: 0; - padding: 4px; - overflow: auto; - border: 1px solid #dce1e5; - border-radius: 6px; - background: #ffffff; -} - -.resolve-context { - margin: 0; - padding: 2px 8px; - overflow-x: auto; - font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; - font-size: 12px; - line-height: 1.5; - tab-size: 2; - color: #3a444c; -} + --color-primary: #256f8f; + --color-primary-dark: #1f5f7b; + --color-accent: #4f7d96; -.resolve-conflict { - display: grid; - gap: 6px; - padding: 8px; - border: 1px solid #e3b778; - border-radius: 6px; - background: #fffaf1; -} - -.resolve-conflict.unresolved { - border-color: #d98b8b; - background: #fff5f3; -} - -.resolve-conflict-bar { - display: flex; - align-items: center; - justify-content: space-between; - flex-wrap: wrap; - gap: 8px; -} - -.resolve-conflict-label { - color: #8a4c0e; - font-size: 12px; - font-weight: 800; -} - -.resolve-choice-buttons { - display: flex; - flex-wrap: wrap; - gap: 4px; -} - -.resolve-choice-buttons button { - min-height: 26px; - padding: 0 8px; - font-size: 12px; -} - -.resolve-choice-buttons button.active { - border-color: #2f6fb0; - color: #ffffff; - background: #2f6fb0; -} - -.resolve-side { - display: grid; - gap: 3px; - padding: 6px; - border: 1px solid #dce1e5; - border-radius: 6px; - border-left-width: 3px; -} - -.resolve-side.ours { - border-left-color: #4aa777; - background: #f1faf4; -} - -.resolve-side.theirs { - border-left-color: #5a8bd0; - background: #f1f5fc; -} - -.resolve-side.dimmed { - opacity: 0.45; - filter: grayscale(0.4); -} - -.resolve-side-label { - font-size: 11px; - font-weight: 800; - text-transform: uppercase; -} - -.resolve-side.ours .resolve-side-label { - color: #1f7a4d; -} - -.resolve-side.theirs .resolve-side-label { - color: #2f6fb0; -} - -.resolve-lines { - margin: 0; - overflow-x: auto; - font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; - font-size: 12px; - line-height: 1.5; - tab-size: 2; -} - -.resolve-line { - display: block; - white-space: pre-wrap; - word-break: break-word; -} - -.resolve-line.ours { - color: #176239; -} - -.resolve-line.theirs { - color: #255b8b; -} - -.resolve-line.context { - color: #3a444c; -} - -.resolve-binary { - display: grid; - align-content: start; - gap: 12px; - padding: 4px; -} + --color-bar: #1a1f23; + --color-bar-text: #c8d0d6; + --color-bar-muted: #8fa8b8; -.resolve-binary-note { - display: flex; - align-items: center; - gap: 8px; - padding: 10px; - border: 1px solid #e3b778; - border-radius: 6px; - color: #8a4c0e; - background: #fff6e7; - font-size: 13px; + --font-mono: "Cascadia Code", "SFMono-Regular", Consolas, monospace; } -.resolve-binary-options { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 10px; -} - -.resolve-binary-card { - display: grid; - gap: 6px; - justify-items: start; - padding: 14px; - border: 1px solid #dce1e5; - border-left-width: 3px; - border-radius: 8px; - text-align: left; -} - -.resolve-binary-card.ours { - border-left-color: #4aa777; - background: #f1faf4; -} - -.resolve-binary-card.theirs { - border-left-color: #5a8bd0; - background: #f1f5fc; -} - -.resolve-binary-card.active { - box-shadow: 0 0 0 2px #2f6fb0 inset; - border-color: #2f6fb0; -} - -.resolve-binary-card strong { - color: #202326; - font-size: 18px; -} - -.resolve-binary-hint { - color: #6c7882; - font-size: 12px; -} - -.resolve-actions { - display: flex; - align-items: center; - justify-content: space-between; - gap: 10px; -} - -.resolve-path { - overflow: hidden; - color: #6c7882; - font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; - font-size: 12px; - text-overflow: ellipsis; - white-space: nowrap; -} - -.diff-counts { - display: flex; - gap: 8px; - font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; - font-size: 12px; - font-weight: 700; -} - -.diff-counts .adds { - color: #176239; -} - -.diff-counts .dels { - color: #9b2e29; -} - -.diff-view { - min-height: 0; - max-height: 420px; - margin: 0; - padding: 10px; - overflow: auto; - border: 1px solid #dce1e5; - border-radius: 6px; - background: #ffffff; - font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; - font-size: 12px; - line-height: 1.5; - tab-size: 2; -} - -.diff-line { - display: block; - white-space: pre-wrap; - word-break: break-word; -} - -.diff-line.meta { - color: #6c7882; -} - -.diff-line.hunk { - color: #255b8b; - background: #eef4fb; -} - -.diff-line.add { - color: #176239; - background: #e6f5ec; -} - -.diff-line.del { - color: #9b2e29; - background: #fdeceb; -} - -.diff-line.context { - color: #3a444c; -} - -.blank-state, -.empty-note { - display: grid; - place-items: center; - min-height: 120px; - margin: 0; - padding: 18px; - color: #6c7882; - font-size: 13px; - text-align: center; -} - -.empty-note { - min-height: 100%; -} - -.spin { - animation: spin 900ms linear infinite; -} - -@keyframes spin { - to { - transform: rotate(360deg); - } -} - -@media (max-width: 1320px) { - .workspace { - grid-template-columns: 300px minmax(0, 1fr) 380px; - } -} - -@media (max-width: 1120px) { - .workspace { - grid-template-columns: 260px minmax(0, 1fr) 330px; - } - - .status-grid { - grid-template-columns: minmax(0, 1fr); - } - - .commit-panel { - min-height: 260px; - } - - .side-stack { - min-height: 760px; - } -} +@layer base { + *, *::before, *::after { box-sizing: border-box; } -@media (max-width: 860px) { + html, body, #app { width: 100%; height: 100%; margin: 0; } body { + overflow: hidden; + color: var(--color-ink); + background: var(--color-surface-alt); + font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + + button, input, textarea, select { font: inherit; } + + button { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 7px; + min-height: 32px; + padding: 0 12px; + border: 1px solid var(--color-border-input); + border-radius: 6px; + color: var(--color-ink); + background: #ffffff; + cursor: pointer; + transition: background 140ms ease, border-color 140ms ease, color 140ms ease; + } + button:hover:not(:disabled) { border-color: #8fa0ad; background: var(--color-surface-hover); } + button:disabled { cursor: not-allowed; opacity: 0.55; } + + input, textarea { + width: 100%; + border: 1px solid var(--color-border-input); + border-radius: 6px; + color: var(--color-ink); + background: #ffffff; + outline: none; + } + input:focus, textarea:focus { + border-color: #2f7da1; + box-shadow: 0 0 0 3px rgba(47, 125, 161, 0.14); + } + input { height: 34px; padding: 0 11px; } + textarea { resize: vertical; min-height: 132px; padding: 10px 11px; line-height: 1.45; } +} + +@layer components { + /* --- Shared utilities --- */ + + .btn-sm { min-height: 28px; padding: 0 8px; font-size: 12px; } + + .btn-primary { + border-color: var(--color-primary); + color: #ffffff; + background: var(--color-primary); + } + .btn-primary:hover:not(:disabled) { + border-color: var(--color-primary-dark); + background: var(--color-primary-dark); + } + + .panel { + min-height: 0; + border: 1px solid var(--color-border); + border-radius: 8px; + background: var(--color-surface); + } + + .section-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + min-height: 58px; + padding: 12px; + border-bottom: 1px solid var(--color-border-subtle); + } + .section-head h2 { margin: 1px 0 0; color: var(--color-ink); font-size: 16px; line-height: 1.2; } + + .eyebrow { + display: block; + color: var(--color-ink-muted); + font-size: 11px; + font-weight: 800; + text-transform: uppercase; + } + + .pill { + display: inline-flex; + align-items: center; + min-height: 24px; + padding: 0 8px; + border-radius: 999px; + font-size: 12px; + font-weight: 700; + white-space: nowrap; + } + .pill-count { color: #4f5d66; background: #edf0f2; } + .pill-active { color: #176239; background: #e4f4ea; } + + .blank-state { + display: grid; + place-items: center; + min-height: 120px; + padding: 18px; + color: var(--color-ink-faint); + font-size: 13px; + text-align: center; + } + + .status-badge { + display: inline-block; + min-width: 74px; + padding: 3px 7px; + border-radius: 999px; + font-size: 11px; + font-weight: 800; + text-align: center; + text-transform: uppercase; + white-space: nowrap; + } + .status-badge.modified { color: #7b4a05; background: #ffe8bb; } + .status-badge.added, + .status-badge.untracked { color: #176239; background: #dff3e7; } + .status-badge.deleted { color: #9b2e29; background: #ffe1df; } + .status-badge.renamed { color: #255b8b; background: #e0effd; } + .status-badge.conflicted { color: #8f2d61; background: #fde2f0; } + .status-badge.unknown, + .status-badge.none { color: #596670; background: #e9edef; } + + .quiet { overflow: hidden; color: #7d8891; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; } + + .spin { animation: spin 900ms linear infinite; } + + /* --- App shell --- */ + + .shell { display: flex; flex-direction: column; height: 100%; background: var(--color-surface-alt); } + + .shell-body { + display: flex; + flex-direction: column; + flex: 1 1 0; + min-height: 0; + padding: 0 12px 12px; + gap: 10px; + } + + /* --- Titlebar --- */ + + .titlebar { + display: grid; + grid-template-columns: auto 1fr auto; + align-items: center; + height: 38px; + background: var(--color-bar); + color: var(--color-bar-text); + user-select: none; + flex-shrink: 0; + -webkit-app-region: drag; + } + + .titlebar-brand { + display: flex; + align-items: center; + gap: 7px; + padding: 0 14px; + height: 100%; + font-size: 13px; + font-weight: 700; + letter-spacing: 0.01em; + color: var(--color-bar-text); + border-right: 1px solid rgba(255,255,255,0.07); + } + .titlebar-brand svg { color: #5da8d4; flex-shrink: 0; } + + .titlebar-info { + display: flex; + align-items: center; + gap: 6px; + padding: 0 12px; + min-width: 0; + height: 100%; + overflow: hidden; + } + .titlebar-info svg { color: #5da8d4; flex-shrink: 0; } + + .tb-repo { color: #7e9aaa; font-size: 12px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 160px; } + .tb-sep { color: #3d4f5c; font-size: 13px; } + .tb-branch { color: #dce6eb; font-size: 12px; font-weight: 700; font-family: var(--font-mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 220px; } + + .tb-sync { display: inline-flex; align-items: center; padding: 1px 6px; border-radius: 999px; font-size: 11px; font-weight: 800; white-space: nowrap; flex-shrink: 0; } + .tb-sync.ahead { color: #f0b861; background: rgba(240,184,97,0.12); } + .tb-sync.behind { color: #79b8e8; background: rgba(121,184,232,0.12); } + + .tb-no-repo { color: #4a5a66; font-size: 12px; font-style: italic; } + + .titlebar-right { display: flex; align-items: stretch; height: 100%; border-left: 1px solid rgba(255,255,255,0.07); } + .titlebar-actions { display: flex; align-items: stretch; } + + .tb-action { + display: flex; + align-items: center; + gap: 5px; + height: 100%; + min-height: unset; + padding: 0 10px; + border: none; + border-radius: 0; + background: transparent; + color: var(--color-bar-muted); + font-size: 12px; + cursor: pointer; + transition: background 120ms ease, color 120ms ease; + -webkit-app-region: no-drag; + } + .tb-action:hover:not(:disabled) { background: rgba(255,255,255,0.08); border-color: transparent; color: #dce6eb; } + .tb-action:disabled { opacity: 0.35; cursor: not-allowed; } + .tb-action.auto-toggle.active { color: #5cba87; } + .tb-action.auto-toggle.active:hover:not(:disabled) { color: #7ad4a2; background: rgba(92,186,135,0.1); } + .tb-action-label { font-size: 12px; font-weight: 600; } + + .titlebar-divider { width: 1px; margin: 8px 0; background: rgba(255,255,255,0.1); flex-shrink: 0; } + + .titlebar-controls { display: flex; align-items: stretch; height: 100%; } + + .tb-btn { + display: flex; + align-items: center; + justify-content: center; + width: 46px; + height: 100%; + min-height: unset; + padding: 0; + border: none; + border-radius: 0; + background: transparent; + color: #7a8e9a; + cursor: pointer; + transition: background 120ms ease, color 120ms ease; + -webkit-app-region: no-drag; + } + .tb-btn:hover:not(:disabled) { background: rgba(255,255,255,0.1); border-color: transparent; color: #ffffff; } + .tb-btn.close:hover:not(:disabled) { background: #c0392b; color: #ffffff; } + + /* --- Top bar (repo form) --- */ + + .topbar { padding: 10px; border: 1px solid var(--color-border); border-radius: 8px; background: var(--color-surface); } + + .repo-form { + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + align-items: center; + gap: 9px; + } + .repo-form label { color: #54606a; font-size: 12px; font-weight: 700; text-transform: uppercase; white-space: nowrap; } + + /* --- Notices --- */ + + .notice { + display: flex; + align-items: center; + gap: 8px; + min-height: 36px; + padding: 8px 11px; + border: 1px solid; + border-radius: 8px; + font-size: 13px; + } + .notice.error { border-color: #e8aaa4; color: #8e2d27; background: #fff4f2; } + .notice.busy { border-color: #a7cfe2; color: #245d78; background: #edf8fd; } + .notice.conflict { border-color: #e3b778; color: #8a4c0e; background: #fff6e7; } + .notice.conflict button { + margin-left: auto; + min-height: 30px; + padding: 0 12px; + border-color: #e3b778; + color: #8a4c0e; + background: #ffffff; + font-size: 13px; + font-weight: 700; + } + + /* --- Workspace layout --- */ + + .workspace { + display: grid; + grid-template-columns: clamp(240px, 22vw, 320px) minmax(0, 1fr) clamp(300px, 30vw, 440px); + flex: 1 1 0; + min-height: 0; + gap: 10px; + } + + .history-aside { display: grid; min-height: 0; } + + .left-sidebar { + display: grid; + grid-template-rows: minmax(220px, 0.9fr) minmax(260px, 1.1fr); + min-height: 0; + gap: 10px; + } + + /* --- Main panel --- */ + + .main-panel { + display: grid; + grid-template-rows: auto minmax(0, 1.2fr) minmax(0, 0.8fr) auto; + min-height: 0; + border: 1px solid var(--color-border); + border-radius: 8px; + background: var(--color-surface); overflow: auto; } - .shell { - min-height: 100%; + .repo-summary { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 12px; + padding: 16px; + border-bottom: 1px solid var(--color-border-subtle); + } + .repo-summary h1 { margin: 1px 0 0; font-size: 24px; line-height: 1.15; } + .repo-summary p { overflow: hidden; margin: 5px 0 0; color: var(--color-ink-dim); font-size: 13px; text-overflow: ellipsis; white-space: nowrap; } + + .sync-stats, .status-counts { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; justify-content: flex-end; } + .sync-stats strong:first-of-type { color: #8a4c0e; background: #fff2d7; } + .sync-stats strong:last-of-type { color: #255b8b; background: #e7f1fb; } + .sync-stats span { color: #4f5d66; background: #edf0f2; } + + .top-section { + display: grid; + grid-template-columns: minmax(0, 1fr) 360px; + min-height: 0; + gap: 10px; + padding: 10px; + overflow: hidden; } - .topbar, - .repo-form, - .workspace, - .repo-summary, - .change-lanes, - .compare-form { - grid-template-columns: 1fr; + .file-history-section { + min-height: 0; + padding: 0 10px 10px; + overflow: hidden; + display: grid; } - .compare-arrow { - display: none; + /* --- File list / change lanes --- */ + + .file-list { padding: 8px; overflow: auto; } + + .file-row { display: grid; gap: 8px; padding: 10px; border: 1px solid var(--color-border-subtle); border-radius: 8px; background: #ffffff; } + .file-row + .file-row { margin-top: 8px; } + + .file-title strong { + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-family: var(--font-mono); + font-size: 13px; } - .dialog-body { - grid-template-columns: 1fr; - grid-template-rows: minmax(120px, 0.4fr) minmax(0, 1fr); - } - - .dialog-files { - border-right: none; - border-bottom: 1px solid #dce1e5; - } - - .toolbar, - .sync-stats { - justify-content: flex-start; - } - - .branch-actions { - justify-content: flex-start; - } - - .history-aside { - min-height: 480px; - } - - .branches { - min-height: 260px; - } - - .left-sidebar { - min-height: 560px; - } + .change-lanes { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; } .change-lane { - grid-template-columns: auto auto; + display: grid; + grid-template-rows: auto auto; + gap: 6px; + padding: 8px; + border: 1px solid var(--color-border-subtle); + border-radius: 6px; + background: var(--color-surface-dim); + } + .change-lane.inactive { color: #8a949c; background: #fafafa; } + .lane-header { display: flex; align-items: center; gap: 8px; } + .lane-name { color: var(--color-ink-quiet); font-size: 12px; font-weight: 800; flex-shrink: 0; } + .lane-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } + + .status-toolbar { + display: flex; + align-items: center; + gap: 6px; + padding: 6px 8px; + border-bottom: 1px solid var(--color-border-subtle); + background: var(--color-surface-dim); } - .lane-actions { - grid-column: 1 / -1; - justify-content: flex-start; + /* --- Branch list --- */ + + .branch-group-label { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + margin: 2px 2px 6px; + color: var(--color-ink-muted); + font-size: 11px; + font-weight: 800; + letter-spacing: 0.04em; + text-transform: uppercase; } + .branch-group-count { + display: inline-flex; + align-items: center; + min-height: 18px; + padding: 0 7px; + border-radius: 999px; + color: #4f5d66; + background: #edf0f2; + font-size: 11px; + } + + .branch-row { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + align-items: center; + gap: 8px; + min-height: 48px; + padding: 8px; + border: 1px solid transparent; + border-radius: 8px; + } + .branch-row + .branch-row { margin-top: 4px; } + .branch-row.current { border-color: #b9ddc6; background: #f0f8f3; } + + .branch-info { display: flex; align-items: center; min-width: 0; gap: 8px; } + .branch-info div { min-width: 0; } + .branch-info strong { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; } + .branch-info span { display: block; margin-top: 2px; color: var(--color-ink-muted); font-size: 12px; } + + .branch-actions { display: flex; align-items: center; justify-content: flex-end; gap: 6px; } + + /* --- Explorer --- */ + + .explorer-row { + display: grid; + grid-template-columns: auto auto minmax(0, 1fr) auto; + align-items: center; + gap: 7px; + width: 100%; + min-height: 34px; + padding: 5px 8px 5px calc(8px + var(--depth, 0) * 14px); + border: 1px solid var(--color-border-input); + border-radius: 6px; + background: #ffffff; + text-align: left; + transition: background 140ms ease, border-color 140ms ease; + } + .explorer-row + .explorer-row { margin-top: 4px; } + .explorer-row:hover { border-color: #8fa0ad; background: var(--color-surface-hover); } + .explorer-row.active { border-color: #9fc8dc; background: #edf8fd; } + .explorer-row.folder { font-weight: 800; } + .explorer-row svg { color: var(--color-accent); } + + .tree-toggle, .explorer-select { min-height: 22px; padding: 0; border: 0; background: transparent; } + .tree-toggle { width: 14px; } + .tree-toggle:hover:not(:disabled), .explorer-select:hover:not(:disabled) { background: transparent; } + .explorer-select { justify-content: flex-start; min-width: 0; } + .tree-spacer { width: 14px; } + .explorer-select span { overflow: hidden; font-family: var(--font-mono); font-size: 12px; font-weight: 700; text-overflow: ellipsis; white-space: nowrap; } + + /* --- Commit form --- */ + + .commit-form { display: flex; flex-direction: column; flex: 1 1 0; min-height: 0; gap: 10px; padding: 12px; } + .commit-form textarea { flex: 1 1 0; min-height: 80px; resize: none; } + + /* --- Commit history --- */ + + .history-list { padding: 8px; overflow: auto; } + + .commit-row { display: grid; gap: 8px; padding: 10px; border: 1px solid var(--color-border-subtle); border-radius: 8px; background: #ffffff; } + .commit-row + .commit-row { margin-top: 8px; } + .commit-row.compact { padding: 9px; } + + .commit-line { display: flex; align-items: flex-start; min-width: 0; gap: 8px; } + .commit-line svg { flex: 0 0 auto; margin-top: 2px; color: var(--color-accent); } + .commit-line div { min-width: 0; } + .commit-line strong { display: block; overflow: hidden; color: var(--color-ink); font-size: 13px; line-height: 1.3; text-overflow: ellipsis; white-space: nowrap; } + .commit-line span { display: block; overflow: hidden; margin-top: 3px; color: var(--color-ink-muted); font-family: var(--font-mono); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; } + + .ref-list { display: flex; flex-wrap: wrap; gap: 5px; } + .ref-list span { max-width: 100%; overflow: hidden; padding: 3px 7px; border-radius: 999px; color: #255b8b; background: #e7f1fb; font-size: 11px; font-weight: 800; text-overflow: ellipsis; white-space: nowrap; } + + .commit-files { display: grid; gap: 6px; } + .commit-files-toggle { justify-content: flex-start; gap: 5px; min-height: 26px; padding: 0 8px; border-color: transparent; background: transparent; color: #4f5d66; font-size: 12px; font-weight: 700; } + .commit-files-toggle:hover:not(:disabled) { border-color: var(--color-border-input); background: var(--color-surface-hover); } + + .commit-file-list { display: grid; gap: 5px; } + .commit-file-button { display: grid; grid-template-columns: auto minmax(0, 1fr); justify-content: stretch; width: 100%; min-height: 30px; padding: 5px 7px; text-align: left; } + .commit-file-button strong { overflow: hidden; color: var(--color-ink); font-family: var(--font-mono); font-size: 12px; font-weight: 700; text-overflow: ellipsis; white-space: nowrap; } + + .commit-actions { display: flex; align-items: center; justify-content: space-between; gap: 8px; } + .commit-actions time { overflow: hidden; color: var(--color-ink-faint); font-size: 12px; text-overflow: ellipsis; white-space: nowrap; } + .commit-action-buttons { display: flex; align-items: center; gap: 6px; } + + /* --- Git graph --- */ + + .graph-list { padding: 0; } + + .graph-row { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 0; margin: 0; padding: 0; border: none; border-radius: 0; background: none; } + .graph-row + .graph-row { margin-top: 0; } + + .graph-gutter { position: relative; align-self: stretch; background: #fdfdfe; } + .graph-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; } + .graph-dot { + position: absolute; + top: 50%; + width: 11px; + height: 11px; + border-radius: 999px; + background: var(--dot-color, #2f6fb0); + border: 2px solid #ffffff; + box-shadow: 0 0 0 1px var(--dot-color, #2f6fb0); + transform: translate(-50%, -50%); + } + .graph-dot.merge { width: 13px; height: 13px; background: #ffffff; border-color: var(--dot-color, #2f6fb0); } + + .commit-body { display: grid; gap: 8px; min-width: 0; padding: 11px 12px; } + .graph-row + .graph-row .commit-body { border-top: 1px solid #e7ebee; } + .graph-row:hover .commit-body { background: #f6f9fb; } + + /* --- Compare panel --- */ + + .compare-panel { + display: grid; + grid-template-rows: auto auto; + margin: 0 10px 10px; + } + + .compare-form { + display: grid; + grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto; + align-items: end; + gap: 10px; + padding: 12px; + border-bottom: 1px solid var(--color-border-subtle); + } + .compare-field { display: grid; gap: 5px; min-width: 0; } + .compare-field span { color: var(--color-ink-quiet); font-size: 12px; font-weight: 800; } + .compare-field select { width: 100%; min-height: 36px; padding: 0 8px; border: 1px solid #c4ccd3; border-radius: 6px; background: #ffffff; color: var(--color-ink); font-size: 13px; } + .compare-arrow { margin-bottom: 8px; color: var(--color-accent); } + + .compare-summary { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px; padding: 12px; } + .compare-range { display: flex; align-items: center; gap: 8px; color: var(--color-accent); } + .compare-range .hash, .dialog-range .hash { padding: 3px 8px; border-radius: 999px; background: #e7f1fb; color: #255b8b; font-family: var(--font-mono); font-size: 12px; font-weight: 700; } + .compare-count { color: var(--color-ink-quiet); font-size: 13px; font-weight: 700; } + + /* --- Dialogs --- */ + + .dialog-backdrop { + position: fixed; + inset: 0; + z-index: 50; + display: grid; + place-items: center; + padding: 24px; + background: rgba(20, 26, 31, 0.45); + } + + .dialog { + display: grid; + grid-template-rows: auto minmax(0, 1fr); + width: min(1100px, 100%); + height: min(760px, 100%); + border: 1px solid #c4ccd3; + border-radius: 12px; + background: var(--color-surface); + box-shadow: 0 18px 48px rgba(20, 26, 31, 0.32); + overflow: hidden; + } + + .dialog-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px; border-bottom: 1px solid var(--color-border-subtle); } + + .dialog-range { display: flex; align-items: center; gap: 8px; margin: 2px 0 0; color: var(--color-accent); font-size: 16px; } + .dialog-title { margin: 2px 0 0; color: var(--color-ink); font-size: 16px; } + + .dialog-close { min-height: 34px; min-width: 34px; padding: 0; justify-content: center; } + + .dialog-body { display: grid; grid-template-columns: 300px minmax(0, 1fr); min-height: 0; } + + .dialog-files { display: grid; align-content: start; gap: 5px; padding: 10px; overflow: auto; border-right: 1px solid var(--color-border-subtle); background: #f4f6f8; } + + .dialog-file-row { + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + align-items: center; + gap: 8px; + padding: 7px 8px; + border: 1px solid var(--color-border-subtle); + border-radius: 6px; + background: #ffffff; + text-align: left; + } + .dialog-file-row.active { border-color: #9cc2e6; background: #e7f1fb; } + .dialog-file-row.prepared { border-color: #b9ddc6; background: #f0f8f3; } + .dialog-file-row.prepared.active { border-color: #4aa777; background: #e4f4ea; } + .dialog-file-row strong { overflow: hidden; color: var(--color-ink); font-family: var(--font-mono); font-size: 12px; font-weight: 700; text-overflow: ellipsis; white-space: nowrap; } + .dialog-file-row svg { color: #1f7a4d; } + + .dialog-diff { display: grid; min-height: 0; padding: 10px; } + .dialog-diff .diff-view { max-height: none; } + + .dialog-footer { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 16px; border-top: 1px solid var(--color-border-subtle); background: #f4f6f8; } + .dialog-footer-info { color: #4f5d66; font-size: 13px; font-weight: 700; } + + .prepared-tag { display: inline-flex; align-items: center; gap: 4px; margin-right: auto; color: #1f7a4d; font-size: 12px; font-weight: 700; } + + /* --- Diff viewer --- */ + + .diff-view { + min-height: 0; + max-height: 420px; + margin: 0; + padding: 10px; + overflow: auto; + border: 1px solid var(--color-border-subtle); + border-radius: 6px; + background: #ffffff; + font-family: var(--font-mono); + font-size: 12px; + line-height: 1.5; + tab-size: 2; + } + .diff-line { display: block; white-space: pre-wrap; word-break: break-word; } + .diff-line.meta { color: var(--color-ink-faint); } + .diff-line.hunk { color: #255b8b; background: #eef4fb; } + .diff-line.add { color: #176239; background: #e6f5ec; } + .diff-line.del { color: #9b2e29; background: #fdeceb; } + .diff-line.context { color: #3a444c; } + + .diff-counts { display: flex; gap: 8px; font-family: var(--font-mono); font-size: 12px; font-weight: 700; } + .diff-counts .adds { color: #176239; } + .diff-counts .dels { color: #9b2e29; } + + /* --- Conflict resolver --- */ + + .resolve-editor { display: flex; flex-direction: column; min-height: 0; padding: 10px; gap: 8px; } + + .resolve-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; } + .resolve-toolbar button { min-height: 32px; padding: 0 10px; font-size: 13px; } + .resolve-toolbar-label { color: var(--color-ink-quiet); font-size: 12px; font-weight: 800; } + + .resolve-status { display: inline-flex; align-items: center; gap: 5px; margin-left: auto; font-size: 12px; font-weight: 700; color: #8a4c0e; } + + .resolve-textarea { + width: 100%; + flex: 1 1 auto; + min-height: 120px; + padding: 10px; + border: 1px solid #c4ccd3; + border-radius: 6px; + background: #ffffff; + color: var(--color-ink); + font-family: var(--font-mono); + font-size: 12px; + line-height: 1.5; + tab-size: 2; + resize: none; + white-space: pre; + } + + .resolve-structured { + display: grid; + align-content: start; + gap: 8px; + flex: 1 1 auto; + min-height: 0; + padding: 4px; + overflow: auto; + border: 1px solid var(--color-border-subtle); + border-radius: 6px; + background: #ffffff; + } + + .resolve-context { margin: 0; padding: 2px 8px; overflow-x: auto; font-family: var(--font-mono); font-size: 12px; line-height: 1.5; tab-size: 2; color: #3a444c; } + + .resolve-conflict { display: grid; gap: 6px; padding: 8px; border: 1px solid #e3b778; border-radius: 6px; background: #fffaf1; } + .resolve-conflict.unresolved { border-color: #d98b8b; background: #fff5f3; } + .resolve-conflict-bar { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px; } + .resolve-conflict-label { color: #8a4c0e; font-size: 12px; font-weight: 800; } + + .resolve-choice-buttons { display: flex; flex-wrap: wrap; gap: 4px; } + .resolve-choice-buttons button { min-height: 26px; padding: 0 8px; font-size: 12px; } + .resolve-choice-buttons button.active { border-color: #2f6fb0; color: #ffffff; background: #2f6fb0; } + + .resolve-side { display: grid; gap: 3px; padding: 6px; border: 1px solid var(--color-border-subtle); border-radius: 6px; border-left-width: 3px; } + .resolve-side.ours { border-left-color: #4aa777; background: #f1faf4; } + .resolve-side.theirs { border-left-color: #5a8bd0; background: #f1f5fc; } + .resolve-side.dimmed { opacity: 0.45; filter: grayscale(0.4); } + + .resolve-side-label { font-size: 11px; font-weight: 800; text-transform: uppercase; } + .resolve-side.ours .resolve-side-label { color: #1f7a4d; } + .resolve-side.theirs .resolve-side-label { color: #2f6fb0; } + + .resolve-lines { margin: 0; overflow-x: auto; font-family: var(--font-mono); font-size: 12px; line-height: 1.5; tab-size: 2; } + .resolve-line { display: block; white-space: pre-wrap; word-break: break-word; } + .resolve-line.ours { color: #176239; } + .resolve-line.theirs { color: #255b8b; } + .resolve-line.context { color: #3a444c; } + + .resolve-binary { display: grid; align-content: start; gap: 12px; padding: 4px; } + .resolve-binary-note { display: flex; align-items: center; gap: 8px; padding: 10px; border: 1px solid #e3b778; border-radius: 6px; color: #8a4c0e; background: #fff6e7; font-size: 13px; } + .resolve-binary-options { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; } + + .resolve-binary-card { display: grid; gap: 6px; justify-items: start; padding: 14px; border: 1px solid var(--color-border-subtle); border-left-width: 3px; border-radius: 8px; text-align: left; } + .resolve-binary-card.ours { border-left-color: #4aa777; background: #f1faf4; } + .resolve-binary-card.theirs { border-left-color: #5a8bd0; background: #f1f5fc; } + .resolve-binary-card.active { box-shadow: 0 0 0 2px #2f6fb0 inset; border-color: #2f6fb0; } + .resolve-binary-card strong { color: var(--color-ink); font-size: 18px; } + .resolve-binary-hint { color: var(--color-ink-faint); font-size: 12px; } + + .resolve-actions { display: flex; align-items: center; justify-content: space-between; gap: 10px; } + .resolve-path { overflow: hidden; color: var(--color-ink-faint); font-family: var(--font-mono); font-size: 12px; text-overflow: ellipsis; white-space: nowrap; } +} + +@keyframes spin { to { transform: rotate(360deg); } } + +/* --- Responsive breakpoints --- */ + +@media (max-width: 1400px) { + .workspace { grid-template-columns: clamp(220px, 20vw, 300px) minmax(0, 1fr) clamp(280px, 28vw, 400px); } +} + +@media (max-width: 1180px) { + .workspace { grid-template-columns: clamp(200px, 18vw, 260px) minmax(0, 1fr) clamp(260px, 26vw, 340px); } + .top-section { grid-template-columns: minmax(0, 1fr); } + .file-history-section { padding: 0 10px 10px; } + .repo-summary h1 { font-size: 20px; } +} + +@media (max-width: 980px) { + .workspace { grid-template-columns: 200px minmax(0, 1fr) 240px; } + .left-sidebar { grid-template-rows: minmax(180px, 0.8fr) minmax(220px, 1.2fr); } + .section-head { min-height: 50px; padding: 10px; } + .repo-summary { padding: 12px; } + .branch-actions { flex-direction: column; align-items: flex-end; gap: 4px; } + .branch-actions button { width: 100%; } +} + +@media (max-width: 860px) { + body { overflow: auto; } + .shell-body { min-height: 100%; } + .repo-form { grid-template-columns: 1fr; } + .workspace { grid-template-columns: 1fr; } + .repo-summary { grid-template-columns: 1fr; } + .change-lanes, .compare-form { grid-template-columns: 1fr; } + .compare-arrow { display: none; } + .dialog-body { grid-template-columns: 1fr; grid-template-rows: minmax(120px, 0.4fr) minmax(0, 1fr); } + .dialog-files { border-right: none; border-bottom: 1px solid var(--color-border-subtle); } + .sync-stats { justify-content: flex-start; } + .branch-actions { flex-direction: row; justify-content: flex-start; } + .tb-action-label { display: none; } + .history-aside { min-height: 480px; } + .branches { min-height: 260px; } + .left-sidebar { min-height: 560px; } + .change-lane { grid-template-columns: auto auto; } + .lane-actions { grid-column: 1 / -1; justify-content: flex-start; } +} + +@media (min-width: 1800px) { + .workspace { grid-template-columns: 360px minmax(0, 1fr) 500px; } + .top-section { grid-template-columns: minmax(0, 1fr) 420px; } } diff --git a/src/lib/TitleBar.svelte b/src/lib/TitleBar.svelte new file mode 100644 index 0000000..cfe8623 --- /dev/null +++ b/src/lib/TitleBar.svelte @@ -0,0 +1,173 @@ + + +
+ +
+ + GitLite +
+ + +
+ {#if hasRepository} + {#if repoName} + {repoName} + + {/if} +
+ + +
+ + + + +
+ + + +
+
+
diff --git a/src/lib/components/BranchPanel.svelte b/src/lib/components/BranchPanel.svelte new file mode 100644 index 0000000..616a69f --- /dev/null +++ b/src/lib/components/BranchPanel.svelte @@ -0,0 +1,107 @@ + + +
+
+
+ Branches +

Refs

+
+ {branches.length} +
+ + {#if !hasRepository} +

Open a repository to list branches.

+ {:else if branches.length === 0} +

No branches returned.

+ {:else} +
+ {#if localBranches.length > 0} +
+ Local + {localBranches.length} +
+ {#each localBranches as branch (branch.name)} + {#snippet branchCard()} +
+
+
+ {#if branch.current} + Current + {:else} +
+ + +
+ {/if} +
+ {/snippet} + {@render branchCard()} + {/each} + {/if} + + {#if remoteBranches.length > 0} +
+ Remote + {remoteBranches.length} +
+ {#each remoteBranches as branch (branch.name)} +
+
+
+ {#if branch.current} + Current + {:else} +
+ + +
+ {/if} +
+ {/each} + {/if} +
+ {/if} +
diff --git a/src/lib/components/CommitPanel.svelte b/src/lib/components/CommitPanel.svelte new file mode 100644 index 0000000..c46d8c7 --- /dev/null +++ b/src/lib/components/CommitPanel.svelte @@ -0,0 +1,57 @@ + + +
+
+
+ Commit +

Message

+
+ {stagedCount} staged +
+ +
+ + +
+
diff --git a/src/lib/components/CompareDialog.svelte b/src/lib/components/CompareDialog.svelte new file mode 100644 index 0000000..421ef60 --- /dev/null +++ b/src/lib/components/CompareDialog.svelte @@ -0,0 +1,143 @@ + + + diff --git a/src/lib/components/ComparePanel.svelte b/src/lib/components/ComparePanel.svelte new file mode 100644 index 0000000..714635c --- /dev/null +++ b/src/lib/components/ComparePanel.svelte @@ -0,0 +1,121 @@ + + +
+
+
+ Compare +

Commits

+
+ {#if comparison} + {comparison.files.length} files + {/if} +
+ + {#if !hasRepository} +
No repository loaded.
+ {:else if commits.length < 2} +
At least two commits are needed to compare.
+ {:else} +
+ + +
diff --git a/src/lib/components/ExplorerPanel.svelte b/src/lib/components/ExplorerPanel.svelte new file mode 100644 index 0000000..946801f --- /dev/null +++ b/src/lib/components/ExplorerPanel.svelte @@ -0,0 +1,170 @@ + + +
+
+
+ Explorer +

Files

+
+ {repoFiles.length} +
+ + {#if !hasRepository} +

Open a repository to browse files.

+ {:else if repoFiles.length === 0} +

No files returned.

+ {:else} +
+ {#each visibleNodes as node (`${node.kind}:${node.path}`)} +
+ {#if node.kind === "folder"} + + {#if expandedExplorerPaths.has(node.path)} +
+ {/each} +
+ {/if} +
diff --git a/src/lib/components/FileHistoryPanel.svelte b/src/lib/components/FileHistoryPanel.svelte new file mode 100644 index 0000000..fd977cf --- /dev/null +++ b/src/lib/components/FileHistoryPanel.svelte @@ -0,0 +1,76 @@ + + +
+
+
+ {selectedExplorerLabel} +

{selectedExplorerPath || "No file"}

+
+ {fileHistory.length} +
+ + {#if !hasRepository} +
No repository loaded.
+ {:else if !selectedExplorerPath} +
Select a file in Explorer.
+ {:else if fileHistory.length === 0} +
No history returned for this selection.
+ {:else} +
+ {#each fileHistory as item (item.hash)} +
+
+
+ +
+ +
+ + +
+
+
+ {/each} +
+ {/if} +
diff --git a/src/lib/components/HistoryPanel.svelte b/src/lib/components/HistoryPanel.svelte new file mode 100644 index 0000000..407698a --- /dev/null +++ b/src/lib/components/HistoryPanel.svelte @@ -0,0 +1,234 @@ + + +
+
+
+ History +

Commits

+
+ {commits.length} +
+ + {#if !hasRepository} +
No repository loaded.
+ {:else if commits.length === 0} +
No commits returned.
+ {:else} +
+ {#each commits as item, rowIndex (item.hash)} + {@const row = graphRows[rowIndex]} +
+ + +
+
+
+ {item.summary} + {item.short_hash} - {item.author_name} +
+
+ + {#if item.refs.length > 0} +
+ {#each item.refs as ref} + {ref} + {/each} +
+ {/if} + + {#if item.files.length > 0} +
+ + + {#if expandedCommitHashes.has(item.hash)} +
+ {#each item.files as file (`${item.hash}:${file.old_path ?? ""}:${file.path}`)} + + {/each} +
+ {/if} +
+ {/if} + +
+ +
+ +
+
+
+
+ {/each} +
+ {/if} +
diff --git a/src/lib/components/ResolveDialog.svelte b/src/lib/components/ResolveDialog.svelte new file mode 100644 index 0000000..c8d54af --- /dev/null +++ b/src/lib/components/ResolveDialog.svelte @@ -0,0 +1,356 @@ + + + diff --git a/src/lib/components/StatusPanel.svelte b/src/lib/components/StatusPanel.svelte new file mode 100644 index 0000000..ba498bd --- /dev/null +++ b/src/lib/components/StatusPanel.svelte @@ -0,0 +1,143 @@ + + +
+
+
+ Working tree +

Status

+
+
+ {stagedCount} staged + {unstagedCount} unstaged +
+
+ + {#if hasRepository && changedFiles.length > 0} +
+ + +
+ {/if} + + {#if !hasRepository} +
No repository loaded.
+ {:else if status?.clean} +
Working tree is clean.
+ {:else if changedFiles.length === 0} +
No file changes returned.
+ {:else} +
+ {#each changedFiles as file (`${file.old_path ?? ""}:${file.path}`)} +
+
+ {displayPath(file)} +
+ +
+
+
+ Staged + {statusLabel(file.staged)} +
+
+ {#if file.staged} + + + {:else} + No staged change + {/if} +
+
+ +
+
+ Unstaged + {statusLabel(file.unstaged)} +
+
+ {#if file.unstaged} + + + {:else} + No unstaged change + {/if} +
+
+
+
+ {/each} +
+ {/if} +
diff --git a/src/lib/types.ts b/src/lib/types.ts index 54a0f00..5dcacfa 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -71,6 +71,28 @@ export interface GitCommitComparison { patch: string; } +export type ExplorerNodeKind = "folder" | "file"; + +export interface ExplorerNode { + name: string; + path: string; + kind: ExplorerNodeKind; + status: FileStatusKind | null; + tracked: boolean; + depth: number; + children: ExplorerNode[]; +} + +export type ConflictChoice = "ours" | "theirs" | "both-ot" | "both-to"; + +export type ConflictPart = + | { kind: "text"; lines: string[] } + | { kind: "conflict"; index: number; oursLines: string[]; theirsLines: string[] }; + +export type PreparedResolution = + | { kind: "content"; content: string } + | { kind: "side"; side: "ours" | "theirs" }; + export interface ConflictFile { path: string; content: string; diff --git a/vite.config.ts b/vite.config.ts index da81787..ceb0a45 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,8 +1,9 @@ import { svelte } from "@sveltejs/vite-plugin-svelte"; +import tailwindcss from "@tailwindcss/vite"; import { defineConfig } from "vite"; export default defineConfig({ - plugins: [svelte()], + plugins: [tailwindcss(), svelte()], clearScreen: false, server: { strictPort: true,