Files
andrew 4e6d665c59 Branch menu UI and remote branch checkout
Add UI improvements and switching state for branch menu and implement remote-branch-aware checkout logic.

Frontend: add CSS for disabled branch items, compact branch name layout, subtitles and messages; show switching indicator and disable branch actions while switching; display local/remote names and remote subtitles; surface branch switch errors and in-progress messages. Add state.branches.switchingTo and update event handlers to set/clear it.

Backend (tauri): extend LocalRepoBranch with is_remote, remote_name, local_name; add git_ref_exists helper; enhance checkout_branch to detect local vs remote refs and automatically checkout or create tracking branches for remotes; parse refs to include remote branches (skip ones with existing local counterparts) and sort branches with current/local/remote order. Minor formatting tweaks.
2026-05-14 17:45:35 +12:00

1983 lines
41 KiB
CSS
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ── App shell ────────────────────────────────────────────────────────────── */
#app {
width: 100%;
height: 100%;
overflow: hidden;
background: var(--bg-app);
}
#app[data-platform="macos"] {
border-radius: var(--radius-window);
}
.layout {
display: grid;
grid-template-rows: 48px 1fr;
grid-template-columns: 320px minmax(0, 1fr);
width: 100%;
height: 100%;
background: var(--bg-app);
}
/* ── Sidebar ──────────────────────────────────────────────────────────────── */
.gd-left {
display: flex;
flex-direction: column;
background: var(--bg-panel);
border-right: 1px solid var(--border);
overflow: hidden;
min-height: 0;
grid-row: 2;
}
.gd-main {
overflow: auto;
background: var(--bg-app);
min-width: 0;
grid-row: 2;
}
/* ── Layout utilities ─────────────────────────────────────────────────────── */
.panel {
border: 1px solid var(--border);
border-radius: var(--radius-lg);
background: var(--bg-panel);
box-shadow: var(--shadow);
padding: 16px;
}
.stack {
display: flex;
flex-direction: column;
gap: 12px;
}
.row {
display: flex;
gap: 8px;
}
.row.wrap {
flex-wrap: wrap;
}
.row.end {
justify-content: flex-end;
}
.gd-path-picker {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 8px;
align-items: center;
}
.gd-editor-picker {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 8px;
align-items: center;
}
/* ── Typography ───────────────────────────────────────────────────────────── */
.muted {
color: var(--text-muted);
}
.label {
font-size: 12px;
color: var(--text-muted);
margin-bottom: 4px;
font-weight: 500;
}
.title {
margin: 0;
font-size: 17px;
font-weight: 600;
color: var(--text-main);
}
.subtitle {
margin: 0;
font-size: 13px;
color: var(--text-muted);
}
.hidden {
display: none !important;
}
.gd-lucide-icon {
display: inline-block;
flex-shrink: 0;
vertical-align: -0.15em;
}
.gd-folder-icon {
color: #54aeff;
}
.gd-file-icon {
color: #848d97;
}
.accent {
color: var(--accent);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 12px;
}
/* ── Welcome view ─────────────────────────────────────────────────────────── */
.welcome-wrap {
min-height: 100%;
display: grid;
place-items: center;
padding: 32px 24px;
background: var(--bg-app);
}
.welcome-card {
width: min(680px, 100%);
}
.welcome-logo {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 4px;
}
.welcome-logo-img {
height: 34px;
width: auto;
}
.welcome-logo-desktop {
font-size: 19px;
font-weight: 300;
color: var(--text-muted);
}
/* ── Toolbar ──────────────────────────────────────────────────────────────── */
.gd-toolbar {
--mac-window-controls-width: 80px;
display: flex;
align-items: stretch;
grid-column: 1 / -1;
grid-row: 1;
background: linear-gradient(180deg, var(--bg-panel-lift) 0%, var(--bg-panel) 100%);
border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
/* Left section matches sidebar width */
.gd-toolbar-left {
display: grid;
grid-template-columns: 1fr 1fr;
width: 320px;
flex-shrink: 0;
border-right: 1px solid rgba(229, 161, 62, 0.12);
}
/* Center section grows */
.gd-toolbar-center {
flex: 1;
display: flex;
align-items: center;
gap: 14px;
padding: 0 18px;
min-width: 0;
}
.gd-toolbar-drag-space {
align-self: stretch;
flex: 1;
min-width: 40px;
}
/* Right section view toggle + utility menu */
.gd-toolbar-right {
display: flex;
align-items: center;
gap: 10px;
padding: 0 14px;
border-left: 1px solid rgba(229, 161, 62, 0.12);
flex-shrink: 0;
}
.gd-window-controls {
display: flex;
align-items: stretch;
flex-shrink: 0;
border-left: 1px solid rgba(229, 161, 62, 0.12);
}
.gd-window-control {
display: inline-flex;
align-items: center;
justify-content: center;
width: 46px;
height: 100%;
padding: 0;
border: 0;
border-radius: 0;
background: transparent;
color: var(--text-muted);
cursor: pointer;
transition: background 0.12s ease, color 0.12s ease;
}
.gd-window-control:hover {
background: rgba(229, 161, 62, 0.1);
color: var(--text-main);
}
.gd-window-close:hover {
background: var(--danger);
color: #ffffff;
}
.gd-toolbar-macos .gd-window-controls {
align-items: center;
gap: 8px;
width: var(--mac-window-controls-width);
padding: 0 14px;
border-left: 0;
border-right: 1px solid rgba(229, 161, 62, 0.12);
}
.gd-toolbar-macos .gd-toolbar-left {
width: calc(320px - var(--mac-window-controls-width));
}
.gd-toolbar-macos .gd-window-control {
width: 12px;
height: 12px;
border-radius: 999px;
color: rgba(60, 64, 67, 0.72);
}
.gd-toolbar-macos .gd-window-control svg {
opacity: 0;
transform: scale(0.72);
transition: opacity 0.12s ease;
}
.gd-toolbar-macos .gd-window-controls:hover .gd-window-control svg {
opacity: 1;
}
.gd-toolbar-macos .gd-window-close {
background: #ff5f57;
}
.gd-toolbar-macos .gd-window-minimize {
background: #ffbd2e;
}
.gd-toolbar-macos .gd-window-maximize {
background: #28c840;
}
.gd-toolbar-macos .gd-window-control:hover {
color: rgba(36, 41, 47, 0.8);
}
.gd-toolbar-macos .gd-window-close:hover {
background: #ff5f57;
color: rgba(36, 41, 47, 0.8);
}
.gd-external-actions {
display: flex;
align-items: center;
gap: 4px;
}
.gd-icon-action {
display: inline-flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
padding: 0;
border: 1px solid transparent;
border-radius: var(--radius-md);
background: transparent;
color: var(--text-muted);
cursor: pointer;
transition: background 0.1s, color 0.1s, border-color 0.1s;
}
.gd-icon-action:hover:not(:disabled) {
background: var(--bg-hover);
border-color: var(--border);
color: var(--text-main);
}
.gd-icon-action:disabled {
opacity: 0.45;
cursor: default;
}
/* Shared toolbar cell (repo + branch buttons) */
.gd-toolbar-cell {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
align-items: center;
gap: 9px;
width: 100%;
height: 100%;
padding: 0 14px 0 12px;
border: 0;
border-radius: 0;
background: transparent;
color: var(--text-main);
cursor: pointer;
text-align: left;
transition: background 0.1s ease;
}
.gd-repo-cell {
border-right: 1px solid rgba(229, 161, 62, 0.12);
}
.gd-toolbar-cell:hover:not(:disabled) {
background: rgba(229, 161, 62, 0.07);
}
.gd-toolbar-cell:disabled {
cursor: default;
opacity: 0.65;
}
.gd-cell-icon {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
color: var(--text-muted);
flex-shrink: 0;
}
.gd-cell-copy {
min-width: 0;
display: flex;
flex-direction: column;
line-height: 1.2;
}
.gd-cell-label {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--text-muted);
font-size: 10px;
font-weight: 400;
letter-spacing: 0.01em;
}
.gd-cell-value {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-top: 2px;
font-size: 13px;
font-weight: 600;
color: var(--text-main);
}
.gd-cell-caret {
color: var(--text-muted);
flex-shrink: 0;
}
/* Branch dropdown wrap */
.gd-branch-wrap {
position: relative;
}
.gd-branch-toolbar {
grid-template-columns: auto minmax(0, 1fr) 10px;
}
/* ── Contextual sync button ───────────────────────────────────────────────── */
.gd-sync-btn {
display: inline-flex;
align-items: center;
gap: 10px;
height: 32px;
padding: 0 14px;
border: 1px solid var(--border);
border-radius: var(--radius-md);
background: var(--bg-panel-alt);
color: var(--text-main);
cursor: pointer;
transition: background 0.16s ease, border-color 0.16s ease, opacity 0.16s ease, transform 0.16s ease;
white-space: nowrap;
min-width: 160px;
}
.gd-sync-btn:hover:not(:disabled) {
background: var(--bg-hover);
border-color: var(--accent);
box-shadow: 0 0 0 2px var(--accent-glow);
}
.gd-sync-btn:disabled {
opacity: 0.62;
cursor: default;
}
.gd-sync-btn:not(:disabled):active {
transform: translateY(1px);
}
.gd-sync-btn .gd-cell-copy {
line-height: 1.25;
transition: opacity 0.16s ease, transform 0.16s ease;
}
.gd-sync-btn .gd-cell-value {
font-size: 13px;
font-weight: 600;
margin-top: 1px;
transition: color 0.16s ease;
}
.gd-sync-btn .gd-cell-label {
font-size: 10px;
}
.gd-sync-icon {
position: relative;
color: var(--text-muted);
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
transition: color 0.16s ease;
}
.gd-sync-btn:hover:not(:disabled) .gd-sync-icon {
color: var(--accent);
}
.gd-sync-icon::before {
content: "";
position: absolute;
inset: 1px;
border: 2px solid transparent;
border-top-color: var(--accent);
border-right-color: var(--accent);
border-radius: 999px;
opacity: 0;
transform: rotate(0deg);
}
.gd-sync-btn.is-loading .gd-sync-icon::before {
opacity: 1;
animation: gd-sync-progress 0.9s linear infinite;
}
.gd-sync-btn.is-loading .gd-cell-copy {
opacity: 0.82;
}
@keyframes gd-sync-progress {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
/* ── View toggle (Changes / History) ─────────────────────────────────────── */
.gd-view-toggle {
display: flex;
background: var(--bg-app);
border: 1px solid var(--border);
border-radius: 8px;
padding: 2px;
gap: 1px;
}
.gd-view-toggle button {
border: none;
background: transparent;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
padding: 4px 12px;
color: var(--text-muted);
cursor: pointer;
transition: background 0.12s, color 0.12s, box-shadow 0.12s;
height: 26px;
}
.gd-view-toggle button:hover {
background: var(--bg-hover);
color: var(--text-main);
border-color: transparent;
}
.gd-view-toggle button.active {
background: var(--accent-subtle);
color: var(--accent);
font-weight: 600;
box-shadow: 0 0 0 1px var(--accent-glow);
}
/* ── Utility menu ─────────────────────────────────────────────────────────── */
.gd-utility-wrap {
position: relative;
flex-shrink: 0;
}
.gd-utility-btn {
display: flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
padding: 0;
border: 1px solid transparent;
border-radius: var(--radius-md);
background: transparent;
color: var(--text-muted);
cursor: pointer;
transition: background 0.1s, color 0.1s, border-color 0.1s;
}
.gd-utility-btn:hover {
background: var(--bg-hover);
border-color: var(--border);
color: var(--text-main);
}
.gd-utility-menu {
position: absolute;
z-index: 30;
top: calc(100% + 6px);
right: 0;
width: 220px;
padding: 4px;
border: 1px solid var(--border);
border-radius: 10px;
background: var(--bg-panel);
box-shadow: var(--shadow);
}
.gd-utility-menu-item {
display: flex;
align-items: center;
gap: 9px;
width: 100%;
padding: 7px 10px;
border: 0;
border-radius: 6px;
background: transparent;
color: var(--text-main);
font-size: 13px;
text-align: left;
cursor: pointer;
transition: background 0.08s;
}
.gd-utility-menu-item:hover {
background: var(--bg-hover);
border-color: transparent;
}
.gd-utility-menu-item:disabled {
opacity: 0.45;
cursor: default;
}
.gd-utility-menu-item:disabled:hover {
background: transparent;
}
.gd-utility-menu-item svg {
color: var(--text-muted);
flex-shrink: 0;
}
.gd-utility-separator {
height: 1px;
background: var(--border);
margin: 3px 4px;
}
/* ── Branch menu dropdown ─────────────────────────────────────────────────── */
.branch-menu {
position: absolute;
z-index: 20;
top: calc(100% + 4px);
left: 4px;
width: 290px;
max-height: min(520px, calc(100vh - 72px));
overflow: auto;
padding: 6px;
border: 1px solid var(--border);
border-radius: 10px;
background: var(--bg-panel);
box-shadow: var(--shadow);
}
.branch-menu-section + .branch-menu-section {
margin-top: 6px;
padding-top: 6px;
border-top: 1px solid var(--border);
}
.branch-menu-label {
padding: 4px 8px 5px;
color: var(--text-muted);
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
}
.branch-menu-item,
.branch-menu-action {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
padding: 6px 8px;
border: 0;
border-radius: 5px;
background: transparent;
text-align: left;
font-size: 13px;
}
.branch-menu-item:disabled {
cursor: default;
opacity: 0.72;
}
.branch-menu-item.active {
background: var(--accent-subtle);
color: var(--accent);
}
.branch-menu-item:hover,
.branch-menu-action:hover {
background: var(--bg-hover);
border-color: transparent;
}
.branch-menu-item:disabled:hover {
background: transparent;
}
.branch-menu-name {
min-width: 0;
display: flex;
flex-direction: column;
gap: 2px;
}
.branch-menu-name > span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.branch-menu-subtitle,
.branch-current-mark {
color: var(--text-muted);
font-size: 11px;
}
.branch-menu-message {
padding: 6px 8px;
color: var(--text-muted);
font-size: 12px;
}
.danger-subtle {
color: var(--danger);
}
/* ── Left panel content ───────────────────────────────────────────────────── */
.gd-left-content {
flex: 1;
overflow-y: hidden;
overflow-x: hidden;
display: flex;
flex-direction: column;
min-height: 0;
}
.gd-left-empty {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px 16px;
text-align: center;
gap: 4px;
}
.gd-left-empty-minimal {
padding: 16px 12px;
text-align: center;
font-size: 12px;
}
/* ── Changes list ─────────────────────────────────────────────────────────── */
.gd-changes-search-row {
display: grid;
grid-template-columns: 32px 1fr;
gap: 5px;
padding: 7px 8px 6px;
border-bottom: 1px solid var(--border-subtle);
flex-shrink: 0;
}
.gd-history-search-row {
grid-template-columns: 1fr;
}
.gd-filter-menu-btn {
display: flex;
align-items: center;
justify-content: center;
height: 26px;
padding: 0;
color: var(--text-muted);
background: transparent;
border: 1px solid transparent;
border-radius: 5px;
}
.gd-filter-menu-btn:hover {
background: var(--bg-hover);
border-color: var(--border);
color: var(--text-main);
}
.gd-filter-input {
height: 26px;
padding: 3px 8px;
font-size: 12px;
border-color: var(--border);
border-radius: 5px;
background: var(--bg-input);
}
.gd-filter-input:focus {
border-color: var(--accent);
box-shadow: 0 0 0 2px var(--accent-glow);
}
.gd-changes-filter-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
min-height: 28px;
padding: 4px 10px;
border-bottom: 1px solid var(--border-subtle);
flex-shrink: 0;
}
.gd-check-all {
display: flex;
align-items: center;
gap: 6px;
cursor: default;
font-size: 11px;
color: var(--text-muted);
}
.gd-check-all input[type="checkbox"] {
width: 13px;
padding: 0;
accent-color: var(--accent);
}
.gd-changes-list {
flex: 1;
overflow: auto;
min-height: 0;
}
.change-group-title {
padding: 7px 12px 3px;
color: var(--text-muted);
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
}
.change-file-row {
display: grid;
grid-template-columns: 16px 20px minmax(0, 1fr);
align-items: center;
gap: 7px;
width: 100%;
padding: 6px 12px;
border: 0;
border-radius: 0;
background: transparent;
text-align: left;
}
.change-file-row:hover {
background: var(--bg-hover);
}
.change-file-row.active {
background: var(--accent-subtle);
border-left: 2px solid var(--accent);
padding-left: 10px;
}
.change-file-checkbox {
width: 13px;
padding: 0;
accent-color: var(--accent);
}
.change-status {
display: inline-flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
border-radius: 3px;
font-size: 10px;
font-weight: 700;
background: var(--bg-panel-alt);
color: var(--text-muted);
}
.change-status-added,
.change-status-untracked {
color: var(--success);
}
.change-status-deleted,
.change-status-conflicted {
color: var(--danger);
}
.change-status-renamed {
color: var(--accent);
}
.change-file-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 12px;
}
/* ── History list in sidebar ──────────────────────────────────────────────── */
.gd-history-list {
flex: 1;
overflow-y: auto;
display: flex;
flex-direction: column;
}
.gd-history-item {
display: flex;
align-items: center;
gap: 8px;
padding: 7px 12px;
border: 0;
border-radius: 0;
border-bottom: 1px solid var(--border-subtle);
background: transparent;
text-align: left;
cursor: pointer;
color: var(--text-main);
transition: background 0.1s;
}
.gd-history-item:hover {
background: var(--bg-hover);
}
.gd-history-item.active {
background: var(--accent-subtle);
border-left: 2px solid var(--accent);
padding-left: 10px;
}
.gd-history-info {
min-width: 0;
display: flex;
flex-direction: column;
gap: 2px;
}
.gd-history-name {
font-size: 12px;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--text-main);
}
.gd-history-path {
font-size: 10px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* ── Commit panel ─────────────────────────────────────────────────────────── */
.gd-commit-area {
flex-shrink: 0;
padding: 10px;
border-top: 1px solid var(--border);
display: flex;
flex-direction: column;
gap: 6px;
background: var(--bg-panel);
}
.gd-commit-summary {
height: 28px;
padding: 4px 10px;
font-size: 12px;
}
.commit-desc-input {
min-height: 54px;
font-size: 12px;
resize: none;
}
.gd-commit-btn {
width: 100%;
height: 30px;
font-size: 12px;
font-weight: 600;
background: linear-gradient(135deg, var(--accent-strong) 0%, var(--accent) 100%) !important;
border-color: transparent !important;
color: #fff !important;
letter-spacing: 0.01em;
transition: opacity 0.15s ease, box-shadow 0.15s ease !important;
}
.gd-commit-btn:hover:not(:disabled) {
opacity: 0.9;
box-shadow: 0 0 0 3px var(--accent-glow) !important;
}
.gd-commit-btn:disabled {
opacity: 0.4;
}
/* ── Diff view ────────────────────────────────────────────────────────────── */
.diff-preview {
max-height: calc(100vh - 164px);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
overflow: auto;
background: var(--bg-code);
}
.diff-preview-inline {
font-family: ui-monospace, "Cascadia Code", "Fira Code", "Consolas", monospace;
font-size: 12px;
line-height: 1.55;
}
.diff-line {
display: grid;
grid-template-columns: 32px minmax(0, 1fr);
min-height: 20px;
color: var(--code-text);
}
.diff-line code {
padding: 2px 12px 2px 0;
white-space: pre;
}
.diff-gutter {
padding: 2px 8px;
color: var(--code-gutter);
text-align: center;
user-select: none;
border-right: 1px solid rgba(125, 133, 144, 0.18);
}
.diff-line-added { background: rgba(63, 185, 80, 0.1); }
.diff-line-added .diff-gutter { color: var(--success); background: rgba(63, 185, 80, 0.14); }
.diff-line-removed { background: rgba(248, 81, 73, 0.1); }
.diff-line-removed .diff-gutter { color: var(--danger); background: rgba(248, 81, 73, 0.15); }
.diff-line-hunk { color: var(--accent); background: var(--accent-subtle); }
.diff-line-meta { color: var(--text-muted); background: rgba(156, 166, 181, 0.06); }
.diff-binary-image-panel {
display: flex;
flex-direction: column;
gap: 12px;
min-height: 200px;
padding: 12px;
}
.diff-image-preview-frame {
display: flex;
align-items: center;
justify-content: center;
min-height: 120px;
padding: 12px;
border-radius: var(--radius-md);
background: rgba(0, 0, 0, 0.12);
}
.diff-image-preview {
min-width: 96px;
min-height: 96px;
max-width: 100%;
max-height: min(70vh, 720px);
object-fit: contain;
border-radius: var(--radius-md);
}
.diff-binary-caption {
margin: 0;
padding: 12px;
font-family: ui-monospace, "Cascadia Code", "Fira Code", "Consolas", monospace;
font-size: 11px;
line-height: 1.5;
color: var(--text-muted);
white-space: pre-wrap;
word-break: break-word;
border: 1px solid var(--border);
border-radius: var(--radius-md);
background: rgba(0, 0, 0, 0.15);
}
.viewer-image-preview-wrap {
display: flex;
align-items: center;
justify-content: center;
min-height: 160px;
padding: 16px;
border: 1px solid var(--border);
border-radius: var(--radius-lg);
background: var(--bg-code);
}
.viewer-image-preview {
min-width: 96px;
min-height: 96px;
max-width: 100%;
max-height: min(75vh, 800px);
object-fit: contain;
border-radius: var(--radius-md);
}
/* ── Workflow empty state ─────────────────────────────────────────────────── */
.workflow-empty-state {
min-height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 10px;
padding: 48px 24px;
text-align: center;
}
.workflow-empty-icon {
width: 68px;
height: 68px;
display: grid;
place-items: center;
border-radius: 20px;
background: var(--accent-subtle);
color: var(--accent);
border: 1px solid var(--accent-glow);
}
.workflow-empty-icon svg {
width: 44px;
height: 44px;
fill: none;
stroke: currentColor;
stroke-linecap: round;
stroke-linejoin: round;
}
.workflow-empty-state h2 {
margin: 0;
color: var(--text-main);
font-size: 19px;
font-weight: 650;
}
.workflow-empty-state p {
max-width: 400px;
margin: 0;
color: var(--text-muted);
font-size: 13px;
line-height: 1.6;
}
.workflow-empty-actions {
display: flex;
gap: 8px;
margin-top: 4px;
}
/* ── Main area ────────────────────────────────────────────────────────────── */
.gd-main-pad {
padding: 18px 20px;
}
/* ── History detail in main area ──────────────────────────────────────────── */
.commit-message-view {
margin: 0;
padding: 12px;
border: 1px solid var(--border);
border-radius: var(--radius-md);
background: var(--bg-panel-alt);
color: var(--text-main);
white-space: pre-wrap;
font-family: inherit;
font-size: 13px;
}
.changed-files-chip-row {
display: flex;
flex-wrap: wrap;
gap: 5px;
}
.changed-file-chip {
padding: 2px 8px;
border: 1px solid var(--border);
border-radius: 999px;
color: var(--text-muted);
font-size: 11px;
background: var(--bg-panel-alt);
}
/* ── Modal system ─────────────────────────────────────────────────────────── */
.gd-modal-backdrop {
position: fixed;
inset: 0;
z-index: 50;
display: grid;
place-items: center;
padding: 20px;
background: rgba(8, 10, 14, 0.75);
backdrop-filter: blur(2px);
}
.gd-modal {
display: flex;
flex-direction: column;
width: min(540px, 100%);
max-height: calc(100vh - 40px);
border: 1px solid var(--border);
border-radius: 12px;
background: var(--bg-panel);
box-shadow: var(--shadow);
overflow: hidden;
}
.gd-modal-wide {
width: min(860px, calc(100vw - 40px));
}
.gd-modal-full-height {
height: calc(100vh - 40px);
}
.gd-modal-full-height .gd-modal-body {
overflow: hidden;
}
.gd-modal-narrow-dialog {
width: min(480px, 100%);
}
.gd-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 16px;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
.gd-modal-title {
margin: 0;
font-size: 15px;
font-weight: 600;
}
.gd-modal-close {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
padding: 0;
border: 0;
border-radius: 6px;
background: transparent;
color: var(--text-muted);
cursor: pointer;
}
.gd-modal-close:hover {
background: var(--bg-hover);
color: var(--text-main);
border-color: transparent;
}
.gd-modal-body {
flex: 1;
overflow: auto;
min-height: 0;
}
.gd-modal-tabs {
display: flex;
gap: 6px;
padding: 10px 12px;
border-bottom: 1px solid var(--border);
background: var(--bg-panel-alt);
}
.gd-modal-tab {
flex: 1;
justify-content: center;
padding: 7px 10px;
border: 1px solid var(--border);
border-radius: var(--radius-md);
background: transparent;
color: var(--text-muted);
font-size: 13px;
font-weight: 600;
}
.gd-modal-tab:hover {
background: var(--bg-hover);
color: var(--text-main);
}
.gd-modal-tab.active {
border-color: transparent;
background: var(--accent-strong);
color: #fff;
}
.gd-modal-tab-panel {
min-height: 430px;
display: flex;
flex-direction: column;
}
.gd-modal-two-col {
display: grid;
grid-template-columns: 1fr 1fr;
min-height: 100%;
}
.gd-modal-section {
padding: 16px;
display: flex;
flex-direction: column;
gap: 8px;
overflow-y: auto;
}
.gd-modal-section-alt {
background: var(--bg-app);
border-left: 1px solid var(--border);
}
.gd-modal-tab-panel .gd-modal-section-alt {
border-left: 0;
}
.gd-modal-section-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 4px;
}
.gd-modal-section-title {
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-muted);
margin: 0 0 4px;
}
.gd-modal-divider {
height: 1px;
background: var(--border);
margin: 4px 0;
}
.gd-modal-empty {
color: var(--text-muted);
font-size: 13px;
padding: 8px 0;
line-height: 1.5;
}
.gd-modal-list-item {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
padding: 8px 0;
border-bottom: 1px solid var(--border-subtle);
}
.gd-modal-list-item:last-child {
border-bottom: 0;
}
.gd-modal-item-info {
min-width: 0;
display: flex;
flex-direction: column;
gap: 2px;
}
.gd-modal-item-info strong {
font-size: 13px;
font-weight: 600;
color: var(--text-main);
}
.gd-modal-item-info strong.accent {
color: var(--accent);
}
.gd-modal-scroll-list {
flex: 1;
overflow-y: auto;
min-height: 0;
max-height: 300px;
}
.gd-modal-tab-panel .gd-modal-scroll-list {
max-height: none;
}
.gd-modal-scan-list {
display: flex;
flex-direction: column;
max-height: 200px;
overflow-y: auto;
}
.gd-modal-narrow {
max-width: 440px;
margin: 0 auto;
}
.gd-path-text {
font-size: 11px;
font-family: ui-monospace, "Cascadia Code", "Fira Code", Consolas, monospace;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* Viewer modal layout */
.gd-modal-viewer {
display: grid;
grid-template-columns: 240px 1fr;
height: 100%;
min-height: 0;
}
.gd-modal-viewer-sidebar {
display: flex;
flex-direction: column;
border-right: 1px solid var(--border);
overflow: hidden;
background: var(--bg-panel);
}
.gd-modal-viewer-controls {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 8px 10px;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
flex-wrap: wrap;
}
.gd-modal-viewer-main {
overflow: auto;
min-width: 0;
background: var(--bg-app);
display: flex;
flex-direction: column;
}
.gd-viewer-tree {
flex: 1;
overflow-y: auto;
}
/* ── Servers UI ───────────────────────────────────────────────────────────── */
.gd-server-item {
padding: 8px 10px;
border: 1px solid var(--border);
border-radius: var(--radius-md);
background: var(--bg-panel-alt);
}
.gd-server-active {
border-color: var(--accent);
background: var(--accent-subtle);
}
.gd-server-name {
font-size: 13px;
font-weight: 600;
}
.gd-server-url {
font-size: 11px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* ── Repo & org display ───────────────────────────────────────────────────── */
.repo-filter-pills {
display: flex;
gap: 5px;
flex-wrap: wrap;
}
.pill-btn {
padding: 3px 12px;
border-radius: 999px;
border: 1px solid var(--border);
background: transparent;
color: var(--text-muted);
font-size: 12px;
cursor: pointer;
transition: background 0.1s, color 0.1s, border-color 0.1s;
}
.pill-btn:hover {
background: var(--bg-hover);
color: var(--text-main);
border-color: #8b949e;
}
.pill-btn.active {
background: var(--accent-strong);
border-color: transparent;
color: #fff;
}
.repo-owner-group {
padding-bottom: 6px;
}
.repo-owner-group + .repo-owner-group {
margin-top: 10px;
}
.repo-owner-divider {
display: flex;
align-items: center;
gap: 10px;
margin: 2px 0 4px;
color: var(--text-muted);
font-size: 11px;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.repo-owner-divider::after {
content: "";
flex: 1;
height: 1px;
background: var(--border);
}
/* ── Branch dialog ────────────────────────────────────────────────────────── */
.modal-backdrop {
position: fixed;
inset: 0;
z-index: 60;
display: grid;
place-items: center;
padding: 24px;
background: rgba(8, 10, 14, 0.72);
backdrop-filter: blur(2px);
}
.modal-card {
width: min(420px, 100%);
display: flex;
flex-direction: column;
gap: 12px;
padding: 18px;
border: 1px solid var(--border);
border-radius: 12px;
background: var(--bg-panel);
box-shadow: var(--shadow);
}
.modal-card h3,
.modal-card p {
margin: 0;
}
.modal-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
}
.danger-note {
padding: 10px 12px;
border: 1px solid rgba(248, 81, 73, 0.3);
border-radius: var(--radius-md);
color: var(--danger);
background: rgba(248, 81, 73, 0.07);
font-size: 13px;
}
/* ── Repository viewer ────────────────────────────────────────────────────── */
.viewer-crumb-row {
display: flex;
align-items: center;
gap: 2px;
flex-wrap: wrap;
min-width: 0;
}
.viewer-crumb-btn {
padding: 0 2px;
border: 0;
background: transparent;
color: var(--accent);
font-size: 14px;
font-weight: 600;
}
.viewer-crumb-btn:hover {
background: transparent;
border: 0;
text-decoration: underline;
color: var(--accent);
}
.viewer-crumb-sep {
color: var(--text-muted);
font-size: 14px;
font-weight: 300;
padding: 0 2px;
user-select: none;
}
.viewer-row {
display: grid;
grid-template-columns: 20px 1fr auto;
align-items: center;
width: 100%;
gap: 7px;
padding: 7px 12px;
border: 0;
border-radius: 0;
border-bottom: 1px solid var(--border-subtle);
background: var(--bg-panel);
text-align: left;
color: var(--text-main);
font-size: 13px;
cursor: pointer;
transition: background 0.08s ease;
}
.viewer-row:last-child {
border-bottom: 0;
}
.viewer-row:hover {
background: var(--bg-hover);
}
.viewer-row.active {
background: var(--accent-subtle);
}
.viewer-row-icon {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.viewer-row-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.viewer-dir-name {
color: var(--accent);
}
.viewer-row-size {
font-size: 11px;
white-space: nowrap;
text-align: right;
font-variant-numeric: tabular-nums;
}
.viewer-file-panel {
border: 1px solid var(--border);
border-radius: var(--radius-lg);
overflow: hidden;
margin-bottom: 16px;
display: flex;
flex-direction: column;
}
.viewer-file-panel-header {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
padding: 9px 14px;
background: var(--bg-panel-alt);
border-bottom: 1px solid var(--border);
}
.viewer-file-name {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
font-weight: 600;
color: var(--text-main);
}
.viewer-readme-panel {
border: 1px solid var(--border);
border-radius: var(--radius-lg);
overflow: hidden;
margin-bottom: 16px;
}
.viewer-readme-header {
display: flex;
align-items: center;
gap: 8px;
padding: 9px 14px;
background: var(--bg-panel-alt);
border-bottom: 1px solid var(--border);
font-size: 13px;
font-weight: 600;
}
.viewer-readme-body {
background: var(--bg-panel);
}
.viewer-error,
.viewer-loading {
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: 7px 12px;
font-size: 12px;
margin-bottom: 10px;
}
.viewer-error {
border-color: rgba(248, 81, 73, 0.35);
color: var(--danger);
background: rgba(248, 81, 73, 0.08);
}
.viewer-loading {
color: var(--text-muted);
background: var(--bg-app);
}
/* ── Markdown renderer ────────────────────────────────────────────────────── */
.markdown-body {
padding: 20px 24px;
font-family: inherit;
font-size: 14px;
line-height: 1.75;
word-break: break-word;
color: var(--text-main);
background: var(--bg-panel);
}
.markdown-body > :first-child { margin-top: 0; }
.markdown-body > :last-child { margin-bottom: 0; }
.markdown-body h1,
.markdown-body h2 {
padding-bottom: 8px;
border-bottom: 1px solid var(--border);
}
.markdown-body h1 { margin: 0 0 16px; font-size: 26px; }
.markdown-body h2 { margin: 24px 0 12px; font-size: 20px; }
.markdown-body h3 { margin: 20px 0 10px; font-size: 17px; }
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 { margin: 16px 0 8px; }
.markdown-body p { margin: 0 0 12px; }
.markdown-body ul,
.markdown-body ol { margin: 0 0 12px; padding-left: 24px; }
.markdown-body blockquote {
margin: 0 0 12px;
padding: 0 12px;
border-left: 3px solid var(--accent);
color: var(--text-muted);
background: var(--accent-subtle);
border-radius: 0 var(--radius-md) var(--radius-md) 0;
padding: 4px 12px;
}
.markdown-body hr {
height: 1px;
margin: 24px 0;
border: 0;
background: var(--border);
}
.markdown-body a { color: var(--accent); text-decoration: none; }
.markdown-body a:hover { text-decoration: underline; }
.markdown-body code {
padding: 2px 5px;
border-radius: var(--radius-md);
background: var(--bg-panel-alt);
font-family: ui-monospace, "Cascadia Code", "Fira Code", "Consolas", monospace;
font-size: 85%;
}
.markdown-body .markdown-code {
margin: 0 0 12px;
padding: 12px;
overflow: auto;
border-radius: var(--radius-md);
background: var(--bg-code);
color: var(--code-text);
}
.markdown-body .markdown-code code {
padding: 0;
background: transparent;
font-size: 12px;
line-height: 1.6;
}
/* ── Code preview ─────────────────────────────────────────────────────────── */
.code-preview {
flex: 1;
margin: 0;
padding: 14px 16px;
overflow: auto;
background: var(--bg-code);
color: var(--code-text);
font-family: ui-monospace, "Cascadia Code", "Fira Code", "Consolas", monospace;
font-size: 12px;
line-height: 1.7;
white-space: pre;
}
.syntax-keyword { color: #FF7B72; }
.syntax-string { color: #A5D6FF; }
.syntax-comment { color: #7D8590; }
.syntax-number { color: #79C0FF; }
.syntax-key { color: #D2A8FF; }
/* ── Git output ───────────────────────────────────────────────────────────── */
.git-output {
background: var(--bg-code);
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: 10px 12px;
font-size: 11px;
font-family: ui-monospace, "Cascadia Code", "Fira Code", "Consolas", monospace;
color: var(--success);
overflow-x: auto;
white-space: pre-wrap;
word-break: break-word;
margin: 0;
line-height: 1.6;
}
.gd-git-out {
margin: 8px;
font-size: 10px;
}
/* ── Shared empty state ───────────────────────────────────────────────────── */
.empty-state {
grid-column: 1 / -1;
text-align: center;
padding: 40px 16px;
}
.empty-state > div:first-child {
font-size: 14px;
color: var(--text-main);
margin-bottom: 5px;
font-weight: 500;
}
/* ── Responsive ───────────────────────────────────────────────────────────── */
@media (max-width: 860px) {
.layout {
grid-template-columns: 272px minmax(0, 1fr);
}
.gd-toolbar-left {
width: 272px;
}
.gd-modal-two-col {
grid-template-columns: 1fr;
}
.gd-modal-section-alt {
border-left: 0;
border-top: 1px solid var(--border);
}
.gd-modal-viewer {
grid-template-columns: 200px 1fr;
}
}
@media (max-width: 640px) {
.layout {
grid-template-columns: 240px minmax(0, 1fr);
}
.gd-toolbar-left {
width: 240px;
grid-template-columns: 1fr;
}
.gd-branch-wrap {
display: none;
}
/* intentional—branch picker hidden at narrow widths */
}
/* ── Custom scrollbars ────────────────────────────────────────────────────── */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(229, 161, 62, 0.22);
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(229, 161, 62, 0.42);
}
:root[data-theme="light"] ::-webkit-scrollbar-thumb {
background: rgba(197, 123, 39, 0.2);
}
:root[data-theme="light"] ::-webkit-scrollbar-thumb:hover {
background: rgba(197, 123, 39, 0.38);
}
/* ── Light mode modal backdrops ─────────────────────────────────────────── */
:root[data-theme="light"] .gd-modal-backdrop,
:root[data-theme="light"] .modal-backdrop {
background: rgba(80, 55, 20, 0.45);
}
/* ── Light mode syntax highlighting ────────────────────────────────────── */
:root[data-theme="light"] .syntax-keyword { color: #B5261E; }
:root[data-theme="light"] .syntax-string { color: #0A6B3F; }
:root[data-theme="light"] .syntax-comment { color: #7A6A50; }
:root[data-theme="light"] .syntax-number { color: #1A5CB5; }
:root[data-theme="light"] .syntax-key { color: #6B3FA0; }
/* ── Light mode diff gutter border ─────────────────────────────────────── */
:root[data-theme="light"] .diff-gutter {
border-right-color: rgba(139, 122, 96, 0.25);
}
/* ── Accent selection highlight ───────────────────────────────────────────── */
::selection {
background: var(--accent-glow);
color: var(--text-main);
}