diff --git a/src/webviews/apps/plus/home/components/branch-card.ts b/src/webviews/apps/plus/home/components/branch-card.ts
index ce32e68c504ae..55f8ac3d29998 100644
--- a/src/webviews/apps/plus/home/components/branch-card.ts
+++ b/src/webviews/apps/plus/home/components/branch-card.ts
@@ -19,6 +19,7 @@ import '../../../shared/components/rich/issue-icon';
import '../../../shared/components/rich/pr-icon';
import '../../../shared/components/actions/action-item';
import '../../../shared/components/actions/action-nav';
+import '../../shared/components/branch-icon';
import './merge-target-status';
export const branchCardStyles = css`
@@ -335,9 +336,7 @@ export abstract class GlBranchCardBase extends GlElement {
>
-
-
-
+ ${this.renderBranchIcon()}
${this.branch.name}
@@ -355,6 +354,10 @@ export abstract class GlBranchCardBase extends GlElement {
`;
}
+ private renderBranchIcon() {
+ return html``;
+ }
+
protected renderPrItem() {
if (!this.branch.pr) return nothing;
diff --git a/src/webviews/apps/plus/shared/components/branch-icon.ts b/src/webviews/apps/plus/shared/components/branch-icon.ts
new file mode 100644
index 0000000000000..264c9ec6d812a
--- /dev/null
+++ b/src/webviews/apps/plus/shared/components/branch-icon.ts
@@ -0,0 +1,120 @@
+import { css, html, LitElement } from 'lit';
+import { customElement, property } from 'lit/decorators.js';
+
+type StatusType = 'synced' | 'diverged' | 'behind' | 'ahead' | 'changes' | undefined;
+
+@customElement('gl-branch-icon')
+export class GlBranchIcon extends LitElement {
+ static override styles = css`
+ :host {
+ display: inline-flex;
+ width: 16px;
+ height: 16px;
+
+ --gl-icon-color-foreground: var(--vscode-foreground, #c5c5c5);
+
+ --gl-icon-color-status-synced: var(--gl-icon-color-foreground);
+ --gl-icon-color-status-diverged: var(--vscode-gitDecoration-modifiedResourceForeground, #ff5);
+ --gl-icon-color-status-behind: var(--vscode-gitDecoration-deletedResourceForeground, #f05);
+ --gl-icon-color-status-ahead: var(--vscode-gitDecoration-addedResourceForeground, #0f5);
+ --gl-icon-color-status-changes: var(--vscode-gitDecoration-untrackedResourceForeground, #1a79ff);
+ }
+
+ :host-context(.vscode-dark),
+ :host-context(.vscode-high-contrast) {
+ --gl-icon-color-foreground: #c5c5c5;
+ }
+
+ :host-context(.vscode-light),
+ :host-context(.vscode-high-contrast-light) {
+ --gl-icon-color-foreground: #424242;
+ }
+
+ svg {
+ width: 100%;
+ height: 100%;
+ }
+ `;
+
+ @property({ type: Object })
+ branch!: { state?: { ahead: number; behind: number }; workingTreeState?: boolean; worktree?: boolean };
+
+ private get status() {
+ if (!this.branch.state) return undefined;
+
+ let status: StatusType;
+ if (this.branch.state.behind > 0 && this.branch.state.ahead > 0) {
+ status = 'diverged';
+ } else if (this.branch.state.behind > 0) {
+ status = 'behind';
+ } else if (this.branch.state.ahead > 0) {
+ status = 'ahead';
+ } else if (this.branch.workingTreeState) {
+ status = 'changes';
+ } else {
+ status = 'synced';
+ }
+ return status;
+ }
+
+ override render() {
+ if (!this.branch.state) {
+ return html``;
+ }
+
+ const statusColor = this.getStatusCssColor();
+
+ if (this.branch.worktree) {
+ return html`
+
+ `;
+ }
+
+ return html` `;
+ }
+
+ private getStatusCssColor(): string {
+ switch (this.status) {
+ case 'diverged':
+ return 'var(--gl-icon-color-status-diverged)';
+ case 'behind':
+ return 'var(--gl-icon-color-status-behind)';
+ case 'ahead':
+ return 'var(--gl-icon-color-status-ahead)';
+ case 'changes':
+ return 'var(--gl-icon-color-status-changes)';
+ case 'synced':
+ default:
+ return 'var(--gl-icon-color-status-synced)';
+ }
+ }
+}