feat(blame): add file blame dialog with git porcelain parsing
This change introduces a new backend command to fetch file blame using git's line-porcelain output and returns structured per-line metadata. The UI adds a BlameDialog that groups lines by commit, highlights uncommitted changes, and styles the dialog to match the updated theme. - Add get_file_blame command and parsing with uncommitted detection - Wire BlameDialog into the explorer file node actions - Add blame UI component and supporting types and styles
This commit is contained in:
+152
-20
@@ -234,8 +234,7 @@
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 24px;
|
||||
background: rgba(4,8,18,0.58);
|
||||
backdrop-filter: blur(8px);
|
||||
background: #050712;
|
||||
}
|
||||
|
||||
.branch-filter-dialog {
|
||||
@@ -247,8 +246,8 @@
|
||||
border: 1px solid rgba(94,110,156,0.24);
|
||||
border-radius: 10px;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255,255,255,0.045), transparent 70%),
|
||||
var(--color-surface);
|
||||
linear-gradient(180deg, #20253f 0%, #151827 72%),
|
||||
#151827;
|
||||
box-shadow: 0 24px 80px rgba(0,0,0,0.42), inset 0 1px 0 rgba(255,255,255,0.05);
|
||||
}
|
||||
|
||||
@@ -2416,8 +2415,8 @@
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 24px;
|
||||
background: rgba(0, 0, 0, 0.65);
|
||||
backdrop-filter: blur(2px);
|
||||
background-color: #050712;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.dialog {
|
||||
@@ -2427,7 +2426,8 @@
|
||||
height: min(760px, 100%);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 12px;
|
||||
background: var(--color-surface);
|
||||
background-color: #111321;
|
||||
background-image: none;
|
||||
box-shadow: 0 24px 72px rgba(0, 0, 0, 0.6), 0 2px 12px rgba(0,0,0,0.4);
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -2444,6 +2444,11 @@
|
||||
width: min(1320px, calc(100vw - 32px));
|
||||
height: min(860px, calc(100vh - 32px));
|
||||
}
|
||||
.blame-dialog {
|
||||
grid-template-rows: auto minmax(0, 1fr);
|
||||
width: min(1320px, calc(100vw - 32px));
|
||||
height: min(860px, calc(100vh - 32px));
|
||||
}
|
||||
.compare-select-dialog {
|
||||
display: block;
|
||||
width: min(720px, calc(100vw - 32px));
|
||||
@@ -2643,7 +2648,7 @@
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.dialog-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px; border-bottom: 1px solid var(--color-border-subtle); background: var(--color-surface-dim); }
|
||||
.dialog-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px; border-bottom: 1px solid var(--color-border-subtle); background: #171a2b; }
|
||||
.dialog-header > div:first-child { min-width: 0; }
|
||||
.dialog-header-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex: 0 0 auto; min-width: 0; }
|
||||
.compare-restore { max-width: 170px; min-width: 0; }
|
||||
@@ -2657,7 +2662,7 @@
|
||||
.dialog-body { display: grid; grid-template-columns: 280px minmax(0, 1fr); min-height: 0; }
|
||||
.compare-dialog .dialog-body { grid-template-columns: minmax(260px, 320px) minmax(0, 1fr); }
|
||||
|
||||
.dialog-files { display: grid; align-content: start; gap: 4px; padding: 8px; overflow: auto; border-right: 1px solid var(--color-border-subtle); background: var(--color-surface-dim); }
|
||||
.dialog-files { display: grid; align-content: start; gap: 4px; padding: 8px; overflow: auto; border-right: 1px solid var(--color-border-subtle); background: #171a2b; }
|
||||
|
||||
.dialog-file-row {
|
||||
display: grid;
|
||||
@@ -2687,7 +2692,7 @@
|
||||
gap: 8px;
|
||||
padding: 7px 12px;
|
||||
border-bottom: 1px solid var(--color-border-subtle);
|
||||
background: var(--color-surface-dim);
|
||||
background: #171a2b;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 12px;
|
||||
color: var(--color-ink-muted);
|
||||
@@ -2709,7 +2714,7 @@
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
tab-size: 2;
|
||||
background: var(--color-surface-raised);
|
||||
background: #111321;
|
||||
}
|
||||
|
||||
.split-pane {
|
||||
@@ -2733,7 +2738,7 @@
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
.split-span.split-meta { color: var(--color-ink-faint); background: rgba(0,0,0,0.18); font-size: 11px; }
|
||||
.split-span.split-meta { color: var(--color-ink-faint); background: #0c0e18; font-size: 11px; }
|
||||
.split-span.split-hunk { color: #7aacff; background: rgba(122,172,255,0.08); padding: 3px 10px; }
|
||||
|
||||
.split-num {
|
||||
@@ -2743,11 +2748,11 @@
|
||||
font-size: 11px;
|
||||
user-select: none;
|
||||
border-right: 1px solid var(--color-border-subtle);
|
||||
background: rgba(0,0,0,0.14);
|
||||
background: #0d101a;
|
||||
}
|
||||
.split-num.del { background: rgba(232,96,96,0.12); color: rgba(232,96,96,0.6); border-right-color: rgba(232,96,96,0.2); }
|
||||
.split-num.add { background: rgba(78,202,118,0.1); color: rgba(78,202,118,0.6); border-right-color: rgba(78,202,118,0.2); }
|
||||
.split-num.empty { background: rgba(0,0,0,0.08); }
|
||||
.split-num.empty { background: #10131e; }
|
||||
|
||||
.split-cell {
|
||||
padding: 0 8px;
|
||||
@@ -2758,7 +2763,7 @@
|
||||
}
|
||||
.split-cell.del { background: rgba(232,96,96,0.1); color: #ef8080; }
|
||||
.split-cell.add { background: rgba(78,202,118,0.09); color: #5dd88a; }
|
||||
.split-cell.empty { background: rgba(0,0,0,0.06); }
|
||||
.split-cell.empty { background: #10131e; }
|
||||
|
||||
/* Search-hit highlight: amber, distinct from add (green) / del (red).
|
||||
Higher specificity so it overrides the add/del backgrounds on a matched line. */
|
||||
@@ -2789,7 +2794,7 @@
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--color-ink-faint);
|
||||
background: rgba(0,0,0,0.1);
|
||||
background: #0d101a;
|
||||
}
|
||||
.split-col-label + .split-col-label { border-left: 1px solid var(--color-border-subtle); }
|
||||
.split-col-hash {
|
||||
@@ -2805,7 +2810,7 @@
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.dialog-footer { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 16px; border-top: 1px solid var(--color-border-subtle); background: var(--color-surface-dim); }
|
||||
.dialog-footer { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 16px; border-top: 1px solid var(--color-border-subtle); background: #171a2b; }
|
||||
.dialog-footer-info { color: var(--color-ink-dim); font-size: 13px; font-weight: 700; }
|
||||
|
||||
.prepared-tag { display: inline-flex; align-items: center; gap: 4px; margin-right: auto; color: #4eca76; font-size: 12px; font-weight: 700; }
|
||||
@@ -2980,6 +2985,134 @@
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
.blame-body {
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
background: #111321;
|
||||
}
|
||||
|
||||
.blame-code-header strong {
|
||||
flex: 0 0 auto;
|
||||
margin-left: auto;
|
||||
color: var(--color-ink-faint);
|
||||
font-size: 11px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.blame-column-headers {
|
||||
grid-template-columns: minmax(300px, 340px) minmax(0, 1fr);
|
||||
}
|
||||
.blame-commit-col-label {
|
||||
padding-left: 12px;
|
||||
}
|
||||
.blame-code-col-label {
|
||||
padding-left: calc(3.2rem + 10px);
|
||||
}
|
||||
.blame-commit-col-label + .blame-code-col-label {
|
||||
border-left: 1px solid var(--color-border-subtle);
|
||||
}
|
||||
|
||||
.blame-diff {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.blame-scroll {
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.blame-code-table {
|
||||
width: max-content;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.blame-group {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(300px, 340px) minmax(max-content, 1fr);
|
||||
align-items: stretch;
|
||||
min-width: max-content;
|
||||
border-bottom: 1px solid var(--color-border-subtle);
|
||||
}
|
||||
.blame-group.uncommitted {
|
||||
background: #171725;
|
||||
}
|
||||
|
||||
.blame-meta {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
min-width: 0;
|
||||
padding: 8px 12px;
|
||||
border-right: 1px solid var(--color-border-subtle);
|
||||
background: #0d101a;
|
||||
box-shadow: 8px 0 18px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
.blame-hash {
|
||||
align-self: flex-start;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
padding: 2px 7px;
|
||||
border: 1px solid rgba(90,140,248,0.2);
|
||||
border-radius: 5px;
|
||||
background: #141b2d;
|
||||
color: var(--color-accent);
|
||||
font-size: 10.5px;
|
||||
font-weight: 700;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.blame-author {
|
||||
overflow: hidden;
|
||||
color: var(--color-ink);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.blame-summary {
|
||||
overflow: hidden;
|
||||
color: #aeb6d8;
|
||||
font-size: 11px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.blame-date {
|
||||
color: var(--color-ink-faint);
|
||||
font-size: 10.5px;
|
||||
}
|
||||
.blame-group:hover .blame-meta {
|
||||
background: #111728;
|
||||
}
|
||||
.blame-group.uncommitted .blame-hash,
|
||||
.blame-group.uncommitted .blame-author {
|
||||
color: #e8b45a;
|
||||
}
|
||||
.blame-group.uncommitted .blame-hash {
|
||||
border-color: rgba(232, 180, 90, 0.26);
|
||||
background: #271f14;
|
||||
}
|
||||
|
||||
.blame-lines {
|
||||
min-width: max-content;
|
||||
grid-template-columns: 4rem minmax(max-content, 1fr);
|
||||
}
|
||||
.blame-line-number {
|
||||
min-height: 20px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
.blame-line-code {
|
||||
min-height: 20px;
|
||||
}
|
||||
.blame-group:hover .blame-line-number {
|
||||
background: #111728;
|
||||
}
|
||||
.blame-group:hover .blame-line-code {
|
||||
background: #151a2b;
|
||||
}
|
||||
|
||||
.global-search-body {
|
||||
display: grid;
|
||||
grid-template-rows: auto auto minmax(0, 1fr);
|
||||
@@ -3370,11 +3503,10 @@
|
||||
border: 1px solid rgba(100, 108, 255, 0.36);
|
||||
border-radius: 14px;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255,255,255,0.06), transparent 42%),
|
||||
rgba(15, 16, 28, 0.96);
|
||||
linear-gradient(180deg, #222743 0%, #111321 42%),
|
||||
#111321;
|
||||
box-shadow: 0 32px 90px rgba(0, 0, 0, 0.68), 0 0 0 1px rgba(255,255,255,0.04) inset;
|
||||
overflow: hidden;
|
||||
backdrop-filter: blur(18px);
|
||||
}
|
||||
|
||||
.cred-hero {
|
||||
|
||||
Reference in New Issue
Block a user