Made more like Github Desktop
This commit is contained in:
+50
-23
@@ -1,18 +1,33 @@
|
||||
:root {
|
||||
--bg-app: #0d1117;
|
||||
--bg-panel: #161b22;
|
||||
--bg-panel-alt: #21262d;
|
||||
--bg-hover: #30363d;
|
||||
--border: #30363d;
|
||||
--text-main: #e6edf3;
|
||||
--text-muted: #848d97;
|
||||
--accent: #2f81f7;
|
||||
--bg-app: #1c2128;
|
||||
--bg-panel: #22272e;
|
||||
--bg-panel-alt: #2a3038;
|
||||
--bg-hover: #2d3540;
|
||||
--border: #1e242b;
|
||||
--text-main: #cdd9e5;
|
||||
--text-muted: #768390;
|
||||
--accent: #58a6ff;
|
||||
--accent-strong: #1f6feb;
|
||||
--success: #3fb950;
|
||||
--danger: #f85149;
|
||||
--radius-md: 6px;
|
||||
--radius-lg: 8px;
|
||||
--shadow: 0 8px 24px rgba(1, 4, 9, 0.75);
|
||||
--shadow: 0 8px 24px rgba(1, 4, 9, 0.7);
|
||||
}
|
||||
|
||||
:root[data-theme="light"] {
|
||||
--bg-app: #f6f8fa;
|
||||
--bg-panel: #ffffff;
|
||||
--bg-panel-alt: #f0f3f6;
|
||||
--bg-hover: #eaeef2;
|
||||
--border: #d0d7de;
|
||||
--text-main: #24292f;
|
||||
--text-muted: #57606a;
|
||||
--accent: #0969da;
|
||||
--accent-strong: #0969da;
|
||||
--success: #1a7f37;
|
||||
--danger: #cf222e;
|
||||
--shadow: 0 8px 24px rgba(31, 35, 40, 0.12);
|
||||
}
|
||||
|
||||
* {
|
||||
@@ -29,6 +44,7 @@ body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
button,
|
||||
@@ -45,40 +61,51 @@ button {
|
||||
color: var(--text-main);
|
||||
padding: 5px 12px;
|
||||
cursor: pointer;
|
||||
transition: background 0.1s ease, border-color 0.1s ease;
|
||||
font-size: 14px;
|
||||
transition: background 0.1s ease, border-color 0.1s ease, opacity 0.1s ease;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: var(--bg-hover);
|
||||
border-color: #8b949e;
|
||||
border-color: #6e7681;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
button:disabled:hover {
|
||||
background: var(--bg-panel-alt);
|
||||
border-color: var(--border);
|
||||
}
|
||||
|
||||
button.primary {
|
||||
background: #238636;
|
||||
border-color: rgba(240, 246, 252, 0.1);
|
||||
border-color: transparent;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
button.primary:hover {
|
||||
background: #2ea043;
|
||||
border-color: rgba(240, 246, 252, 0.1);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
button.primary-blue {
|
||||
background: var(--accent-strong);
|
||||
border-color: rgba(240, 246, 252, 0.1);
|
||||
border-color: transparent;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
button.primary-blue:hover {
|
||||
background: var(--accent);
|
||||
border-color: rgba(240, 246, 252, 0.1);
|
||||
background: #388bfd;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
button.danger {
|
||||
border-color: rgba(248, 81, 73, 0.4);
|
||||
border-color: rgba(248, 81, 73, 0.35);
|
||||
color: #f85149;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
button.danger:hover {
|
||||
@@ -90,12 +117,12 @@ input,
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 5px 12px;
|
||||
padding: 5px 10px;
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--bg-app);
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
color: var(--text-main);
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
transition: border-color 0.1s ease, box-shadow 0.1s ease;
|
||||
}
|
||||
|
||||
@@ -104,10 +131,10 @@ select:focus,
|
||||
textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 0 0 3px rgba(47, 129, 247, 0.15);
|
||||
box-shadow: 0 0 0 3px rgba(31, 111, 235, 0.12);
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 96px;
|
||||
min-height: 80px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
+1176
-557
File diff suppressed because it is too large
Load Diff
+1400
-414
File diff suppressed because it is too large
Load Diff
+59
-4
@@ -1,10 +1,16 @@
|
||||
import { loadSettings, saveSettings } from "./storage.js";
|
||||
|
||||
const initialSettings = loadSettings();
|
||||
|
||||
const state = {
|
||||
settings: loadSettings(),
|
||||
selectedRepoPath: "",
|
||||
selectedRepoName: "",
|
||||
settings: initialSettings,
|
||||
selectedRepoPath: initialSettings.lastSelectedRepoPath || "",
|
||||
selectedRepoName: initialSettings.lastSelectedRepoPath ? initialSettings.lastSelectedRepoPath.split(/[/\\]/).filter(Boolean).pop() || "" : "",
|
||||
repoSearch: "",
|
||||
changesFilter: "",
|
||||
historyFilter: "",
|
||||
commitSummary: "",
|
||||
commitDescription: "",
|
||||
localRepoPathInput: "",
|
||||
localRepoScanRootInput: "",
|
||||
localRepoScanResults: [],
|
||||
@@ -13,6 +19,55 @@ const state = {
|
||||
cloneUrlInput: "",
|
||||
cloneDestinationInput: "",
|
||||
commitMessage: "",
|
||||
workingTree: {
|
||||
loading: false,
|
||||
error: "",
|
||||
branch: "",
|
||||
upstream: "",
|
||||
ahead: 0,
|
||||
behind: 0,
|
||||
files: [],
|
||||
selectedPaths: new Set(),
|
||||
selectedPath: "",
|
||||
selectedDiff: null,
|
||||
diffLoading: false,
|
||||
diffError: "",
|
||||
},
|
||||
sync: {
|
||||
loading: false,
|
||||
error: "",
|
||||
operation: "",
|
||||
branch: "",
|
||||
upstream: "",
|
||||
upstreamRemote: "",
|
||||
defaultRemote: "",
|
||||
ahead: 0,
|
||||
behind: 0,
|
||||
hasRemote: false,
|
||||
isDetached: false,
|
||||
isUnpublished: false,
|
||||
lastUpdated: 0,
|
||||
},
|
||||
branches: {
|
||||
loading: false,
|
||||
error: "",
|
||||
items: [],
|
||||
createName: "",
|
||||
menuOpen: false,
|
||||
dialog: {
|
||||
mode: "",
|
||||
target: "",
|
||||
value: "",
|
||||
error: "",
|
||||
},
|
||||
},
|
||||
history: {
|
||||
loading: false,
|
||||
error: "",
|
||||
commits: [],
|
||||
selectedHash: "",
|
||||
selectedCommit: null,
|
||||
},
|
||||
viewer: {
|
||||
source: "",
|
||||
repoName: "",
|
||||
@@ -47,7 +102,7 @@ export function addRecentRepo(path) {
|
||||
if (!path) return;
|
||||
const current = state.settings.recentRepositories.filter((item) => item !== path);
|
||||
const next = [path, ...current].slice(0, 15);
|
||||
updateSettings({ recentRepositories: next });
|
||||
updateSettings({ recentRepositories: next, lastSelectedRepoPath: path });
|
||||
}
|
||||
|
||||
export function getActiveServer() {
|
||||
|
||||
@@ -5,6 +5,9 @@ export function getDefaultSettings() {
|
||||
theme: "dark",
|
||||
gitExecutablePath: "",
|
||||
defaultCloneDirectory: "",
|
||||
externalEditorPath: "",
|
||||
autoFetchOnRepoOpen: false,
|
||||
lastSelectedRepoPath: "",
|
||||
activeServerId: null,
|
||||
servers: [],
|
||||
recentRepositories: [],
|
||||
|
||||
@@ -25,6 +25,21 @@ export async function runGitPush(repoPath, gitPath) {
|
||||
return invoke("git_push", { repoPath, gitPath: gitPath || null });
|
||||
}
|
||||
|
||||
export async function runGitPublishBranch(repoPath, remote, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("git_publish_branch", { repoPath, remote: remote || null, gitPath: gitPath || null });
|
||||
}
|
||||
|
||||
export async function runGitFetch(repoPath, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("git_fetch", { repoPath, gitPath: gitPath || null });
|
||||
}
|
||||
|
||||
export async function runGitSync(repoPath, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("git_sync", { repoPath, gitPath: gitPath || null });
|
||||
}
|
||||
|
||||
export async function runGitStatus(repoPath, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("git_status", { repoPath, gitPath: gitPath || null });
|
||||
@@ -35,6 +50,87 @@ export async function runGitBranch(repoPath, gitPath) {
|
||||
return invoke("git_branch", { repoPath, gitPath: gitPath || null });
|
||||
}
|
||||
|
||||
export async function getWorkingTreeStatus(repoPath, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("working_tree_status", { repoPath, gitPath: gitPath || null });
|
||||
}
|
||||
|
||||
export async function getRepositorySyncStatus(repoPath, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("repository_sync_status", { repoPath, gitPath: gitPath || null });
|
||||
}
|
||||
|
||||
export async function getFileDiff(repoPath, path, status, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("get_file_diff", { repoPath, path, status, gitPath: gitPath || null });
|
||||
}
|
||||
|
||||
export async function stageFiles(repoPath, paths, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("stage_files", { repoPath, paths, gitPath: gitPath || null });
|
||||
}
|
||||
|
||||
export async function unstageFiles(repoPath, paths, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("unstage_files", { repoPath, paths, gitPath: gitPath || null });
|
||||
}
|
||||
|
||||
export async function commitChanges(repoPath, paths, summary, description, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("commit_changes", {
|
||||
repoPath,
|
||||
paths,
|
||||
summary,
|
||||
description: description || null,
|
||||
gitPath: gitPath || null,
|
||||
});
|
||||
}
|
||||
|
||||
export async function checkoutBranch(repoPath, branch, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("checkout_branch", { repoPath, branch, gitPath: gitPath || null });
|
||||
}
|
||||
|
||||
export async function createBranch(repoPath, branch, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("create_branch", { repoPath, branch, gitPath: gitPath || null });
|
||||
}
|
||||
|
||||
export async function deleteBranch(repoPath, branch, force, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("delete_branch", { repoPath, branch, force: !!force, gitPath: gitPath || null });
|
||||
}
|
||||
|
||||
export async function renameBranch(repoPath, oldBranch, newBranch, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("rename_branch", {
|
||||
repoPath,
|
||||
oldBranch,
|
||||
newBranch,
|
||||
gitPath: gitPath || null,
|
||||
});
|
||||
}
|
||||
|
||||
export async function getCommitHistory(repoPath, limit, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("commit_history", { repoPath, limit, gitPath: gitPath || null });
|
||||
}
|
||||
|
||||
export async function getCommitDetail(repoPath, hash, gitPath) {
|
||||
ensureInvoke();
|
||||
return invoke("commit_detail", { repoPath, hash, gitPath: gitPath || null });
|
||||
}
|
||||
|
||||
export async function openInFileExplorer(repoPath) {
|
||||
ensureInvoke();
|
||||
return invoke("open_in_file_explorer", { repoPath });
|
||||
}
|
||||
|
||||
export async function openInExternalEditor(repoPath, editorPath) {
|
||||
ensureInvoke();
|
||||
return invoke("open_in_external_editor", { repoPath, editorPath });
|
||||
}
|
||||
|
||||
export async function scanLocalRepos(roots = [], allowedRemoteUrls = [], gitPath = "", maxDepth = 4, maxResults = 200) {
|
||||
ensureInvoke();
|
||||
return invoke("scan_local_repos", {
|
||||
|
||||
Reference in New Issue
Block a user