refactor(sidebar): unify left sidebar panel sizing and resize logic
Replace per-panel height constants, state, loaders and resize handlers with a single model for all left sidebar panels. Panel sizes are now stored/read as a JSON object under "gitlite.sidebarPanelHeights.v2" and managed via shared helpers. Key changes and behavior: - Introduce SIDEBAR_PANEL_ORDER, per-panel MIN/DEFAULT heights and a shared MAX/STEP. - Single in-memory map sidebarPanelHeights with clamp/load/persist helpers. - One pointer/keyboard resize flow: startSidebarPanelResize, onSidebarPanelResizeMove, endSidebarPanelResize and onSidebarPanelResizeKeydown. Dragging moves the border between the panel above (grows) and the next expanded panel below (shrinks). The last expanded panel is flexible (1fr) and follows automatically. - Double-click on a handle resets the above/below panels to their defaults. - buildLeftSidebarRows now derives grid rows from the unified state; template uses new handlers and aria attributes. - LocalStorage remains best-effort; persistence failures are ignored as before. Removes many duplicate functions/variables for individual panels and simplifies the UI logic for showing/hiding resize handles and resizing behavior.
This commit is contained in:
+240
-271
@@ -296,10 +296,7 @@
|
|||||||
const AUTO_REFRESH_ENABLED_KEY = "gitlite.autoRefreshEnabled.v1";
|
const AUTO_REFRESH_ENABLED_KEY = "gitlite.autoRefreshEnabled.v1";
|
||||||
const COMMIT_PANEL_HEIGHT_KEY = "gitlite.commitPanelHeight.v1";
|
const COMMIT_PANEL_HEIGHT_KEY = "gitlite.commitPanelHeight.v1";
|
||||||
const LEFT_SIDEBAR_WIDTH_KEY = "gitlite.leftSidebarWidth.v1";
|
const LEFT_SIDEBAR_WIDTH_KEY = "gitlite.leftSidebarWidth.v1";
|
||||||
const LEFT_BRANCH_PANEL_HEIGHT_KEY = "gitlite.leftBranchPanelHeight.v1";
|
const SIDEBAR_PANEL_HEIGHTS_KEY = "gitlite.sidebarPanelHeights.v2";
|
||||||
const LEFT_TAGS_PANEL_HEIGHT_KEY = "gitlite.leftTagsPanelHeight.v1";
|
|
||||||
const LEFT_WORKTREE_PANEL_HEIGHT_KEY = "gitlite.leftWorktreePanelHeight.v1";
|
|
||||||
const LEFT_STASH_PANEL_HEIGHT_KEY = "gitlite.leftStashPanelHeight.v1";
|
|
||||||
const BRANCH_PANEL_COLLAPSED_KEY = "gitlite.branchPanelCollapsed.v1";
|
const BRANCH_PANEL_COLLAPSED_KEY = "gitlite.branchPanelCollapsed.v1";
|
||||||
const STASH_PANEL_COLLAPSED_KEY = "gitlite.stashPanelCollapsed.v2";
|
const STASH_PANEL_COLLAPSED_KEY = "gitlite.stashPanelCollapsed.v2";
|
||||||
const EXPLORER_PANEL_COLLAPSED_KEY = "gitlite.explorerPanelCollapsed.v1";
|
const EXPLORER_PANEL_COLLAPSED_KEY = "gitlite.explorerPanelCollapsed.v1";
|
||||||
@@ -310,13 +307,26 @@
|
|||||||
const LEFT_SIDEBAR_DEFAULT_WIDTH = 280;
|
const LEFT_SIDEBAR_DEFAULT_WIDTH = 280;
|
||||||
const LEFT_SIDEBAR_MIN_WIDTH = 220;
|
const LEFT_SIDEBAR_MIN_WIDTH = 220;
|
||||||
const LEFT_SIDEBAR_MAX_WIDTH = 420;
|
const LEFT_SIDEBAR_MAX_WIDTH = 420;
|
||||||
const LEFT_BRANCH_PANEL_DEFAULT_HEIGHT = 260;
|
// Sidebar panels, top to bottom. A drag handle moves the border between two
|
||||||
const LEFT_BRANCH_PANEL_MIN_HEIGHT = 180;
|
// neighbours: the panel above grows, the next expanded panel below gives way.
|
||||||
const LEFT_BRANCH_PANEL_MAX_HEIGHT = 560;
|
const SIDEBAR_PANEL_ORDER = ["branch", "worktree", "tags", "stash", "explorer"] as const;
|
||||||
const LEFT_STASH_PANEL_DEFAULT_HEIGHT = 190;
|
type SidebarPanelId = (typeof SIDEBAR_PANEL_ORDER)[number];
|
||||||
const LEFT_STASH_PANEL_MIN_HEIGHT = 150;
|
const SIDEBAR_PANEL_MIN_HEIGHT: Record<SidebarPanelId, number> = {
|
||||||
const LEFT_STASH_PANEL_MAX_HEIGHT = 420;
|
branch: 120,
|
||||||
const LEFT_EXPLORER_PANEL_MIN_HEIGHT = 220;
|
worktree: 96,
|
||||||
|
tags: 96,
|
||||||
|
stash: 110,
|
||||||
|
explorer: 140,
|
||||||
|
};
|
||||||
|
const SIDEBAR_PANEL_DEFAULT_HEIGHT: Record<SidebarPanelId, number> = {
|
||||||
|
branch: 260,
|
||||||
|
worktree: 150,
|
||||||
|
tags: 150,
|
||||||
|
stash: 190,
|
||||||
|
explorer: 260,
|
||||||
|
};
|
||||||
|
const SIDEBAR_PANEL_MAX_HEIGHT = 900;
|
||||||
|
const SIDEBAR_RESIZE_STEP = 24;
|
||||||
const HISTORY_ASIDE_DEFAULT_WIDTH = 620;
|
const HISTORY_ASIDE_DEFAULT_WIDTH = 620;
|
||||||
const HISTORY_ASIDE_MIN_WIDTH = 420;
|
const HISTORY_ASIDE_MIN_WIDTH = 420;
|
||||||
const HISTORY_ASIDE_MAX_WIDTH = 920;
|
const HISTORY_ASIDE_MAX_WIDTH = 920;
|
||||||
@@ -553,22 +563,12 @@
|
|||||||
let resizingLeftSidebar = false;
|
let resizingLeftSidebar = false;
|
||||||
let leftSidebarResizeStartX = 0;
|
let leftSidebarResizeStartX = 0;
|
||||||
let leftSidebarResizeStartWidth = 0;
|
let leftSidebarResizeStartWidth = 0;
|
||||||
let leftBranchPanelHeight = loadLeftBranchPanelHeight();
|
let sidebarPanelHeights: Record<SidebarPanelId, number> = loadSidebarPanelHeights();
|
||||||
let resizingLeftBranchPanel = false;
|
let resizingSidebarPanel: SidebarPanelId | null = null;
|
||||||
let leftBranchResizeStartY = 0;
|
let sidebarResizeStartY = 0;
|
||||||
let leftBranchResizeStartHeight = 0;
|
let sidebarResizeAboveStart = 0;
|
||||||
let leftWorktreePanelHeight = loadLeftWorktreePanelHeight();
|
let sidebarResizeBelowStart = 0;
|
||||||
let resizingLeftWorktreePanel = false;
|
let sidebarResizeBelow: SidebarPanelId | null = null;
|
||||||
let leftWorktreeResizeStartY = 0;
|
|
||||||
let leftWorktreeResizeStartHeight = 0;
|
|
||||||
let leftTagsPanelHeight = loadLeftTagsPanelHeight();
|
|
||||||
let resizingLeftTagsPanel = false;
|
|
||||||
let leftTagsResizeStartY = 0;
|
|
||||||
let leftTagsResizeStartHeight = 0;
|
|
||||||
let leftStashPanelHeight = loadLeftStashPanelHeight();
|
|
||||||
let resizingLeftStashPanel = false;
|
|
||||||
let leftStashResizeStartY = 0;
|
|
||||||
let leftStashResizeStartHeight = 0;
|
|
||||||
let tagsPanelCollapsed = loadStoredBoolean("gitlite.tagsPanelCollapsed.v1", true);
|
let tagsPanelCollapsed = loadStoredBoolean("gitlite.tagsPanelCollapsed.v1", true);
|
||||||
let branchPanelCollapsed = loadStoredBoolean(BRANCH_PANEL_COLLAPSED_KEY, false);
|
let branchPanelCollapsed = loadStoredBoolean(BRANCH_PANEL_COLLAPSED_KEY, false);
|
||||||
let stashPanelCollapsed = loadStoredBoolean(STASH_PANEL_COLLAPSED_KEY, true);
|
let stashPanelCollapsed = loadStoredBoolean(STASH_PANEL_COLLAPSED_KEY, true);
|
||||||
@@ -624,7 +624,7 @@
|
|||||||
) as Record<string, string>;
|
) as Record<string, string>;
|
||||||
$: remoteBranches = branches.filter((b) => b.remote);
|
$: remoteBranches = branches.filter((b) => b.remote);
|
||||||
$: currentBranchIsLocalOnly = Boolean(status?.current_branch) && !status?.upstream;
|
$: currentBranchIsLocalOnly = Boolean(status?.current_branch) && !status?.upstream;
|
||||||
$: leftSidebarRows = buildLeftSidebarRows(branchPanelCollapsed, stashPanelCollapsed, explorerPanelCollapsed, worktreePanelCollapsed, tagsPanelCollapsed);
|
$: leftSidebarRows = buildLeftSidebarRows(branchPanelCollapsed, worktreePanelCollapsed, tagsPanelCollapsed, stashPanelCollapsed, explorerPanelCollapsed, sidebarPanelHeights);
|
||||||
$: allLeftPanelsCollapsed = branchPanelCollapsed && worktreePanelCollapsed && tagsPanelCollapsed && stashPanelCollapsed && explorerPanelCollapsed;
|
$: allLeftPanelsCollapsed = branchPanelCollapsed && worktreePanelCollapsed && tagsPanelCollapsed && stashPanelCollapsed && explorerPanelCollapsed;
|
||||||
$: editorToolName = externalToolDisplayName("editor", externalToolsSettings.editor, detectedExternalTools);
|
$: editorToolName = externalToolDisplayName("editor", externalToolsSettings.editor, detectedExternalTools);
|
||||||
$: diffToolName = externalToolDisplayName("diff", externalToolsSettings.diff, detectedExternalTools);
|
$: diffToolName = externalToolDisplayName("diff", externalToolsSettings.diff, detectedExternalTools);
|
||||||
@@ -1976,50 +1976,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function clampLeftBranchPanelHeight(value: number): number {
|
|
||||||
return Math.min(LEFT_BRANCH_PANEL_MAX_HEIGHT, Math.max(LEFT_BRANCH_PANEL_MIN_HEIGHT, Math.round(value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadLeftBranchPanelHeight(): number {
|
|
||||||
try {
|
|
||||||
const stored = Number(localStorage.getItem(LEFT_BRANCH_PANEL_HEIGHT_KEY));
|
|
||||||
if (Number.isFinite(stored) && stored > 0) return clampLeftBranchPanelHeight(stored);
|
|
||||||
} catch {
|
|
||||||
// Fall through to the default below.
|
|
||||||
}
|
|
||||||
return LEFT_BRANCH_PANEL_DEFAULT_HEIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
function persistLeftBranchPanelHeight(value: number) {
|
|
||||||
try {
|
|
||||||
localStorage.setItem(LEFT_BRANCH_PANEL_HEIGHT_KEY, String(value));
|
|
||||||
} catch {
|
|
||||||
// Local storage is best-effort only; resizing must keep working without it.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function clampLeftStashPanelHeight(value: number): number {
|
|
||||||
return Math.min(LEFT_STASH_PANEL_MAX_HEIGHT, Math.max(LEFT_STASH_PANEL_MIN_HEIGHT, Math.round(value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadLeftStashPanelHeight(): number {
|
|
||||||
try {
|
|
||||||
const stored = Number(localStorage.getItem(LEFT_STASH_PANEL_HEIGHT_KEY));
|
|
||||||
if (Number.isFinite(stored) && stored > 0) return clampLeftStashPanelHeight(stored);
|
|
||||||
} catch {
|
|
||||||
// Fall through to the default below.
|
|
||||||
}
|
|
||||||
return LEFT_STASH_PANEL_DEFAULT_HEIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
function persistLeftStashPanelHeight(value: number) {
|
|
||||||
try {
|
|
||||||
localStorage.setItem(LEFT_STASH_PANEL_HEIGHT_KEY, String(value));
|
|
||||||
} catch {
|
|
||||||
// Local storage is best-effort only; resizing must keep working without it.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function clampHistoryAsideWidth(value: number): number {
|
function clampHistoryAsideWidth(value: number): number {
|
||||||
return Math.min(HISTORY_ASIDE_MAX_WIDTH, Math.max(HISTORY_ASIDE_MIN_WIDTH, Math.round(value)));
|
return Math.min(HISTORY_ASIDE_MAX_WIDTH, Math.max(HISTORY_ASIDE_MIN_WIDTH, Math.round(value)));
|
||||||
}
|
}
|
||||||
@@ -2098,176 +2054,172 @@
|
|||||||
persistLeftSidebarWidth(leftSidebarWidth);
|
persistLeftSidebarWidth(leftSidebarWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildLeftSidebarRows(branchCollapsed: boolean, stashCollapsed: boolean, explorerCollapsed: boolean, worktreeCollapsed: boolean, tagsCollapsed: boolean): string {
|
// ── Sidebar panel sizing ───────────────────────────────────────────────────
|
||||||
const branchRow = branchCollapsed
|
|
||||||
? "auto"
|
|
||||||
: `minmax(${LEFT_BRANCH_PANEL_MIN_HEIGHT}px, var(--branch-panel-height, ${LEFT_BRANCH_PANEL_DEFAULT_HEIGHT}px))`;
|
|
||||||
const branchHandleRow = branchCollapsed ? "0" : "6px";
|
|
||||||
const stashRow = stashCollapsed
|
|
||||||
? "auto"
|
|
||||||
: `minmax(${LEFT_STASH_PANEL_MIN_HEIGHT}px, var(--stash-panel-height, ${LEFT_STASH_PANEL_DEFAULT_HEIGHT}px))`;
|
|
||||||
const stashHandleRow = explorerCollapsed || stashCollapsed ? "0" : "6px";
|
|
||||||
const explorerRow = explorerCollapsed ? "auto" : `minmax(${LEFT_EXPLORER_PANEL_MIN_HEIGHT}px, 1fr)`;
|
|
||||||
|
|
||||||
return `${branchRow} ${branchHandleRow} ${worktreeCollapsed ? "42px 0" : "var(--worktree-panel-height, 140px) 6px"} ${tagsCollapsed ? "42px 0" : "var(--tags-panel-height, 140px) 6px"} ${stashRow} ${stashHandleRow} ${explorerRow}`;
|
function clampSidebarPanelHeight(panel: SidebarPanelId, value: number): number {
|
||||||
|
return Math.min(SIDEBAR_PANEL_MAX_HEIGHT, Math.max(SIDEBAR_PANEL_MIN_HEIGHT[panel], Math.round(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function clampLeftWorktreePanelHeight(value: number) {
|
function loadSidebarPanelHeights(): Record<SidebarPanelId, number> {
|
||||||
return Math.min(420, Math.max(80, Math.round(value)));
|
const heights = { ...SIDEBAR_PANEL_DEFAULT_HEIGHT };
|
||||||
}
|
|
||||||
|
|
||||||
function loadLeftWorktreePanelHeight() {
|
|
||||||
try {
|
try {
|
||||||
const stored = Number(localStorage.getItem(LEFT_WORKTREE_PANEL_HEIGHT_KEY));
|
const stored: unknown = JSON.parse(localStorage.getItem(SIDEBAR_PANEL_HEIGHTS_KEY) ?? "{}");
|
||||||
if (Number.isFinite(stored) && stored > 0) return clampLeftWorktreePanelHeight(stored);
|
if (stored && typeof stored === "object") {
|
||||||
} catch { /* Preferences are optional. */ }
|
for (const panel of SIDEBAR_PANEL_ORDER) {
|
||||||
return 140;
|
const value = Number((stored as Record<string, unknown>)[panel]);
|
||||||
|
if (Number.isFinite(value) && value > 0) heights[panel] = clampSidebarPanelHeight(panel, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Stored sizes are a convenience; the defaults above always work.
|
||||||
|
}
|
||||||
|
return heights;
|
||||||
}
|
}
|
||||||
|
|
||||||
function persistLeftWorktreePanelHeight() {
|
function persistSidebarPanelHeights() {
|
||||||
try { localStorage.setItem(LEFT_WORKTREE_PANEL_HEIGHT_KEY, String(leftWorktreePanelHeight)); }
|
|
||||||
catch { /* Preferences are optional. */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
function startLeftWorktreePanelResize(event: PointerEvent) {
|
|
||||||
event.preventDefault();
|
|
||||||
resizingLeftWorktreePanel = true;
|
|
||||||
leftWorktreeResizeStartY = event.clientY;
|
|
||||||
leftWorktreeResizeStartHeight = leftWorktreePanelHeight;
|
|
||||||
(event.currentTarget as HTMLElement).setPointerCapture(event.pointerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onLeftWorktreePanelResizeMove(event: PointerEvent) {
|
|
||||||
if (!resizingLeftWorktreePanel) return;
|
|
||||||
leftWorktreePanelHeight = clampLeftWorktreePanelHeight(leftWorktreeResizeStartHeight + event.clientY - leftWorktreeResizeStartY);
|
|
||||||
}
|
|
||||||
|
|
||||||
function endLeftWorktreePanelResize(event: PointerEvent) {
|
|
||||||
if (!resizingLeftWorktreePanel) return;
|
|
||||||
resizingLeftWorktreePanel = false;
|
|
||||||
persistLeftWorktreePanelHeight();
|
|
||||||
const target = event.currentTarget as HTMLElement;
|
|
||||||
if (target.hasPointerCapture(event.pointerId)) target.releasePointerCapture(event.pointerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onLeftWorktreePanelResizeKeydown(event: KeyboardEvent) {
|
|
||||||
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
|
|
||||||
event.preventDefault();
|
|
||||||
leftWorktreePanelHeight = clampLeftWorktreePanelHeight(leftWorktreePanelHeight + (event.key === "ArrowDown" ? 20 : -20));
|
|
||||||
persistLeftWorktreePanelHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
function clampLeftTagsPanelHeight(value: number) {
|
|
||||||
return Math.min(420, Math.max(80, Math.round(value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadLeftTagsPanelHeight() {
|
|
||||||
try {
|
try {
|
||||||
const stored = Number(localStorage.getItem(LEFT_TAGS_PANEL_HEIGHT_KEY));
|
localStorage.setItem(SIDEBAR_PANEL_HEIGHTS_KEY, JSON.stringify(sidebarPanelHeights));
|
||||||
if (Number.isFinite(stored) && stored > 0) return clampLeftTagsPanelHeight(stored);
|
} catch {
|
||||||
} catch { /* Preferences are optional. */ }
|
// Local storage is best-effort only; resizing must keep working without it.
|
||||||
return 140;
|
|
||||||
}
|
|
||||||
|
|
||||||
function persistLeftTagsPanelHeight() {
|
|
||||||
try { localStorage.setItem(LEFT_TAGS_PANEL_HEIGHT_KEY, String(leftTagsPanelHeight)); }
|
|
||||||
catch { /* Preferences are optional. */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
function startLeftTagsPanelResize(event: PointerEvent) {
|
|
||||||
event.preventDefault();
|
|
||||||
resizingLeftTagsPanel = true;
|
|
||||||
leftTagsResizeStartY = event.clientY;
|
|
||||||
leftTagsResizeStartHeight = leftTagsPanelHeight;
|
|
||||||
(event.currentTarget as HTMLElement).setPointerCapture(event.pointerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onLeftTagsPanelResizeMove(event: PointerEvent) {
|
|
||||||
if (!resizingLeftTagsPanel) return;
|
|
||||||
leftTagsPanelHeight = clampLeftTagsPanelHeight(leftTagsResizeStartHeight + event.clientY - leftTagsResizeStartY);
|
|
||||||
}
|
|
||||||
|
|
||||||
function endLeftTagsPanelResize(event: PointerEvent) {
|
|
||||||
if (!resizingLeftTagsPanel) return;
|
|
||||||
resizingLeftTagsPanel = false;
|
|
||||||
persistLeftTagsPanelHeight();
|
|
||||||
const target = event.currentTarget as HTMLElement;
|
|
||||||
if (target.hasPointerCapture(event.pointerId)) target.releasePointerCapture(event.pointerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onLeftTagsPanelResizeKeydown(event: KeyboardEvent) {
|
|
||||||
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
|
|
||||||
event.preventDefault();
|
|
||||||
leftTagsPanelHeight = clampLeftTagsPanelHeight(leftTagsPanelHeight + (event.key === "ArrowDown" ? 20 : -20));
|
|
||||||
persistLeftTagsPanelHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
function startLeftBranchPanelResize(event: PointerEvent) {
|
|
||||||
if (branchPanelCollapsed) return;
|
|
||||||
event.preventDefault();
|
|
||||||
resizingLeftBranchPanel = true;
|
|
||||||
leftBranchResizeStartY = event.clientY;
|
|
||||||
leftBranchResizeStartHeight = leftBranchPanelHeight;
|
|
||||||
(event.currentTarget as HTMLElement).setPointerCapture(event.pointerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onLeftBranchPanelResizeMove(event: PointerEvent) {
|
|
||||||
if (!resizingLeftBranchPanel) return;
|
|
||||||
leftBranchPanelHeight = clampLeftBranchPanelHeight(leftBranchResizeStartHeight + (event.clientY - leftBranchResizeStartY));
|
|
||||||
}
|
|
||||||
|
|
||||||
function endLeftBranchPanelResize(event: PointerEvent) {
|
|
||||||
if (!resizingLeftBranchPanel) return;
|
|
||||||
resizingLeftBranchPanel = false;
|
|
||||||
persistLeftBranchPanelHeight(leftBranchPanelHeight);
|
|
||||||
const target = event.currentTarget as HTMLElement;
|
|
||||||
if (target.hasPointerCapture(event.pointerId)) target.releasePointerCapture(event.pointerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onLeftBranchPanelResizeKeydown(event: KeyboardEvent) {
|
|
||||||
if (branchPanelCollapsed || (event.key !== "ArrowUp" && event.key !== "ArrowDown")) return;
|
|
||||||
event.preventDefault();
|
|
||||||
leftBranchPanelHeight = clampLeftBranchPanelHeight(leftBranchPanelHeight + (event.key === "ArrowDown" ? 20 : -20));
|
|
||||||
persistLeftBranchPanelHeight(leftBranchPanelHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
function startLeftStashPanelResize(event: PointerEvent) {
|
|
||||||
if (stashPanelCollapsed && branchPanelCollapsed) return;
|
|
||||||
event.preventDefault();
|
|
||||||
resizingLeftStashPanel = true;
|
|
||||||
leftStashResizeStartY = event.clientY;
|
|
||||||
leftStashResizeStartHeight = stashPanelCollapsed ? leftBranchPanelHeight : leftStashPanelHeight;
|
|
||||||
(event.currentTarget as HTMLElement).setPointerCapture(event.pointerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onLeftStashPanelResizeMove(event: PointerEvent) {
|
|
||||||
if (!resizingLeftStashPanel) return;
|
|
||||||
if (stashPanelCollapsed) {
|
|
||||||
leftBranchPanelHeight = clampLeftBranchPanelHeight(leftStashResizeStartHeight + (event.clientY - leftStashResizeStartY));
|
|
||||||
} else {
|
|
||||||
leftStashPanelHeight = clampLeftStashPanelHeight(leftStashResizeStartHeight + (event.clientY - leftStashResizeStartY));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function endLeftStashPanelResize(event: PointerEvent) {
|
function sidebarPanelIsCollapsed(panel: SidebarPanelId): boolean {
|
||||||
if (!resizingLeftStashPanel) return;
|
if (panel === "branch") return branchPanelCollapsed;
|
||||||
resizingLeftStashPanel = false;
|
if (panel === "worktree") return worktreePanelCollapsed;
|
||||||
if (stashPanelCollapsed) persistLeftBranchPanelHeight(leftBranchPanelHeight);
|
if (panel === "tags") return tagsPanelCollapsed;
|
||||||
else persistLeftStashPanelHeight(leftStashPanelHeight);
|
if (panel === "stash") return stashPanelCollapsed;
|
||||||
|
return explorerPanelCollapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Expanded panels, top to bottom. The last one always fills the leftover space. */
|
||||||
|
function expandedSidebarPanels(): SidebarPanelId[] {
|
||||||
|
return SIDEBAR_PANEL_ORDER.filter((panel) => !sidebarPanelIsCollapsed(panel));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The first expanded panel below `panel` — the one that gives way while dragging. */
|
||||||
|
function nextExpandedSidebarPanel(panel: SidebarPanelId): SidebarPanelId | null {
|
||||||
|
const expanded = expandedSidebarPanels();
|
||||||
|
const index = expanded.indexOf(panel);
|
||||||
|
return index >= 0 && index < expanded.length - 1 ? expanded[index + 1] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A handle only makes sense between two expanded panels. */
|
||||||
|
function sidebarHandleVisible(panel: SidebarPanelId, ...markers: boolean[]): boolean {
|
||||||
|
void markers;
|
||||||
|
return !sidebarPanelIsCollapsed(panel) && nextExpandedSidebarPanel(panel) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildLeftSidebarRows(
|
||||||
|
branchCollapsed: boolean,
|
||||||
|
worktreeCollapsed: boolean,
|
||||||
|
tagsCollapsed: boolean,
|
||||||
|
stashCollapsed: boolean,
|
||||||
|
explorerCollapsed: boolean,
|
||||||
|
heights: Record<SidebarPanelId, number>,
|
||||||
|
): string {
|
||||||
|
void branchCollapsed; void worktreeCollapsed; void tagsCollapsed; void stashCollapsed; void explorerCollapsed;
|
||||||
|
|
||||||
|
const expanded = expandedSidebarPanels();
|
||||||
|
const flexible = expanded[expanded.length - 1];
|
||||||
|
const rows: string[] = [];
|
||||||
|
|
||||||
|
for (const panel of SIDEBAR_PANEL_ORDER) {
|
||||||
|
if (sidebarPanelIsCollapsed(panel)) rows.push("auto");
|
||||||
|
else if (panel === flexible) rows.push(`minmax(${SIDEBAR_PANEL_MIN_HEIGHT[panel]}px, 1fr)`);
|
||||||
|
else rows.push(`${heights[panel]}px`);
|
||||||
|
|
||||||
|
if (panel !== "explorer") rows.push(sidebarHandleVisible(panel) ? "8px" : "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows.join(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
function startSidebarPanelResize(event: PointerEvent, panel: SidebarPanelId) {
|
||||||
|
const below = nextExpandedSidebarPanel(panel);
|
||||||
|
if (!below) return;
|
||||||
|
event.preventDefault();
|
||||||
|
resizingSidebarPanel = panel;
|
||||||
|
sidebarResizeBelow = below;
|
||||||
|
sidebarResizeStartY = event.clientY;
|
||||||
|
sidebarResizeAboveStart = sidebarPanelHeights[panel];
|
||||||
|
sidebarResizeBelowStart = sidebarPanelHeights[below];
|
||||||
|
(event.currentTarget as HTMLElement).setPointerCapture(event.pointerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSidebarPanelResizeMove(event: PointerEvent) {
|
||||||
|
const panel = resizingSidebarPanel;
|
||||||
|
if (!panel) return;
|
||||||
|
applySidebarPanelResize(panel, event.clientY - sidebarResizeStartY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move the border by `delta`: the panel above grows, the neighbour below
|
||||||
|
* shrinks by the same amount. The last expanded panel is sized with 1fr, so
|
||||||
|
* it follows on its own and only the panel above needs a new height.
|
||||||
|
*/
|
||||||
|
function applySidebarPanelResize(panel: SidebarPanelId, delta: number) {
|
||||||
|
const below = sidebarResizeBelow;
|
||||||
|
const expanded = expandedSidebarPanels();
|
||||||
|
const belowIsFlexible = below !== null && below === expanded[expanded.length - 1];
|
||||||
|
|
||||||
|
if (below === null) return;
|
||||||
|
|
||||||
|
if (belowIsFlexible) {
|
||||||
|
sidebarPanelHeights = {
|
||||||
|
...sidebarPanelHeights,
|
||||||
|
[panel]: clampSidebarPanelHeight(panel, sidebarResizeAboveStart + delta),
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxGrow = sidebarResizeBelowStart - SIDEBAR_PANEL_MIN_HEIGHT[below];
|
||||||
|
const maxShrink = sidebarResizeAboveStart - SIDEBAR_PANEL_MIN_HEIGHT[panel];
|
||||||
|
const applied = Math.max(-maxShrink, Math.min(maxGrow, Math.round(delta)));
|
||||||
|
|
||||||
|
sidebarPanelHeights = {
|
||||||
|
...sidebarPanelHeights,
|
||||||
|
[panel]: clampSidebarPanelHeight(panel, sidebarResizeAboveStart + applied),
|
||||||
|
[below]: clampSidebarPanelHeight(below, sidebarResizeBelowStart - applied),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function endSidebarPanelResize(event: PointerEvent) {
|
||||||
|
if (!resizingSidebarPanel) return;
|
||||||
|
resizingSidebarPanel = null;
|
||||||
|
sidebarResizeBelow = null;
|
||||||
|
persistSidebarPanelHeights();
|
||||||
const target = event.currentTarget as HTMLElement;
|
const target = event.currentTarget as HTMLElement;
|
||||||
if (target.hasPointerCapture(event.pointerId)) target.releasePointerCapture(event.pointerId);
|
if (target.hasPointerCapture(event.pointerId)) target.releasePointerCapture(event.pointerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onLeftStashPanelResizeKeydown(event: KeyboardEvent) {
|
function onSidebarPanelResizeKeydown(event: KeyboardEvent, panel: SidebarPanelId) {
|
||||||
if ((stashPanelCollapsed && branchPanelCollapsed) || (event.key !== "ArrowUp" && event.key !== "ArrowDown")) return;
|
const below = nextExpandedSidebarPanel(panel);
|
||||||
event.preventDefault();
|
if (!below) return;
|
||||||
if (stashPanelCollapsed) {
|
|
||||||
leftBranchPanelHeight = clampLeftBranchPanelHeight(leftBranchPanelHeight + (event.key === "ArrowDown" ? 20 : -20));
|
if (event.key === "Home") {
|
||||||
persistLeftBranchPanelHeight(leftBranchPanelHeight);
|
event.preventDefault();
|
||||||
} else {
|
resetSidebarPanelHeight(panel);
|
||||||
leftStashPanelHeight = clampLeftStashPanelHeight(leftStashPanelHeight + (event.key === "ArrowDown" ? 20 : -20));
|
return;
|
||||||
persistLeftStashPanelHeight(leftStashPanelHeight);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
sidebarResizeBelow = below;
|
||||||
|
sidebarResizeAboveStart = sidebarPanelHeights[panel];
|
||||||
|
sidebarResizeBelowStart = sidebarPanelHeights[below];
|
||||||
|
applySidebarPanelResize(panel, event.key === "ArrowDown" ? SIDEBAR_RESIZE_STEP : -SIDEBAR_RESIZE_STEP);
|
||||||
|
sidebarResizeBelow = null;
|
||||||
|
persistSidebarPanelHeights();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Double-click on a handle puts the panel above back to its default height. */
|
||||||
|
function resetSidebarPanelHeight(panel: SidebarPanelId) {
|
||||||
|
const below = nextExpandedSidebarPanel(panel);
|
||||||
|
sidebarPanelHeights = { ...sidebarPanelHeights, [panel]: SIDEBAR_PANEL_DEFAULT_HEIGHT[panel] };
|
||||||
|
if (below) sidebarPanelHeights = { ...sidebarPanelHeights, [below]: SIDEBAR_PANEL_DEFAULT_HEIGHT[below] };
|
||||||
|
persistSidebarPanelHeights();
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleBranchPanelCollapsed() {
|
function toggleBranchPanelCollapsed() {
|
||||||
@@ -6153,8 +6105,9 @@
|
|||||||
class:stash-collapsed={stashPanelCollapsed}
|
class:stash-collapsed={stashPanelCollapsed}
|
||||||
class:explorer-collapsed={explorerPanelCollapsed}
|
class:explorer-collapsed={explorerPanelCollapsed}
|
||||||
class:all-collapsed={allLeftPanelsCollapsed}
|
class:all-collapsed={allLeftPanelsCollapsed}
|
||||||
|
class:resizing-panels={resizingSidebarPanel !== null}
|
||||||
aria-label="Repository navigation"
|
aria-label="Repository navigation"
|
||||||
style="--tags-panel-height: {leftTagsPanelHeight}px; --worktree-panel-height: {leftWorktreePanelHeight}px; --branch-panel-height: {leftBranchPanelHeight}px; --stash-panel-height: {leftStashPanelHeight}px; grid-template-rows: {leftSidebarRows};"
|
style="grid-template-rows: {leftSidebarRows};"
|
||||||
>
|
>
|
||||||
<BranchPanel
|
<BranchPanel
|
||||||
{branches}
|
{branches}
|
||||||
@@ -6175,24 +6128,26 @@
|
|||||||
collapsed={branchPanelCollapsed}
|
collapsed={branchPanelCollapsed}
|
||||||
onToggleCollapsed={toggleBranchPanelCollapsed}
|
onToggleCollapsed={toggleBranchPanelCollapsed}
|
||||||
/>
|
/>
|
||||||
{#if !branchPanelCollapsed}
|
{#if sidebarHandleVisible("branch", branchPanelCollapsed, worktreePanelCollapsed, tagsPanelCollapsed, stashPanelCollapsed, explorerPanelCollapsed)}
|
||||||
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
||||||
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
||||||
<div
|
<div
|
||||||
class="panel-resize-handle left-panel-resize-handle branch-panel-resize-handle"
|
class="panel-resize-handle left-panel-resize-handle"
|
||||||
class:resizing={resizingLeftBranchPanel}
|
class:resizing={resizingSidebarPanel === "branch"}
|
||||||
role="separator"
|
role="separator"
|
||||||
aria-orientation="horizontal"
|
aria-orientation="horizontal"
|
||||||
aria-label="Resize branches panel height"
|
aria-label="Resize branches panel height"
|
||||||
aria-valuenow={leftBranchPanelHeight}
|
aria-valuenow={sidebarPanelHeights.branch}
|
||||||
aria-valuemin={LEFT_BRANCH_PANEL_MIN_HEIGHT}
|
aria-valuemin={SIDEBAR_PANEL_MIN_HEIGHT.branch}
|
||||||
aria-valuemax={LEFT_BRANCH_PANEL_MAX_HEIGHT}
|
aria-valuemax={SIDEBAR_PANEL_MAX_HEIGHT}
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
onpointerdown={startLeftBranchPanelResize}
|
title="Drag to move the border · double-click to reset"
|
||||||
onpointermove={onLeftBranchPanelResizeMove}
|
onpointerdown={(event) => startSidebarPanelResize(event, "branch")}
|
||||||
onpointerup={endLeftBranchPanelResize}
|
onpointermove={onSidebarPanelResizeMove}
|
||||||
onpointercancel={endLeftBranchPanelResize}
|
onpointerup={endSidebarPanelResize}
|
||||||
onkeydown={onLeftBranchPanelResizeKeydown}
|
onpointercancel={endSidebarPanelResize}
|
||||||
|
ondblclick={() => resetSidebarPanelHeight("branch")}
|
||||||
|
onkeydown={(event) => onSidebarPanelResizeKeydown(event, "branch")}
|
||||||
></div>
|
></div>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="left-panel-resize-placeholder" aria-hidden="true"></span>
|
<span class="left-panel-resize-placeholder" aria-hidden="true"></span>
|
||||||
@@ -6212,20 +6167,26 @@
|
|||||||
onManage={() => { void openWorktreeDialog(); }}
|
onManage={() => { void openWorktreeDialog(); }}
|
||||||
onRefresh={() => { void refreshWorktrees(); }}
|
onRefresh={() => { void refreshWorktrees(); }}
|
||||||
/>
|
/>
|
||||||
{#if !worktreePanelCollapsed}
|
{#if sidebarHandleVisible("worktree", branchPanelCollapsed, worktreePanelCollapsed, tagsPanelCollapsed, stashPanelCollapsed, explorerPanelCollapsed)}
|
||||||
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
||||||
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
||||||
<div
|
<div
|
||||||
class="panel-resize-handle left-panel-resize-handle worktree-panel-resize-handle"
|
class="panel-resize-handle left-panel-resize-handle"
|
||||||
class:resizing={resizingLeftWorktreePanel}
|
class:resizing={resizingSidebarPanel === "worktree"}
|
||||||
role="separator" aria-orientation="horizontal" aria-label="Resize worktrees panel height"
|
role="separator"
|
||||||
aria-valuenow={leftWorktreePanelHeight} aria-valuemin={80} aria-valuemax={420}
|
aria-orientation="horizontal"
|
||||||
|
aria-label="Resize worktrees panel height"
|
||||||
|
aria-valuenow={sidebarPanelHeights.worktree}
|
||||||
|
aria-valuemin={SIDEBAR_PANEL_MIN_HEIGHT.worktree}
|
||||||
|
aria-valuemax={SIDEBAR_PANEL_MAX_HEIGHT}
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
onpointerdown={startLeftWorktreePanelResize}
|
title="Drag to move the border · double-click to reset"
|
||||||
onpointermove={onLeftWorktreePanelResizeMove}
|
onpointerdown={(event) => startSidebarPanelResize(event, "worktree")}
|
||||||
onpointerup={endLeftWorktreePanelResize}
|
onpointermove={onSidebarPanelResizeMove}
|
||||||
onpointercancel={endLeftWorktreePanelResize}
|
onpointerup={endSidebarPanelResize}
|
||||||
onkeydown={onLeftWorktreePanelResizeKeydown}
|
onpointercancel={endSidebarPanelResize}
|
||||||
|
ondblclick={() => resetSidebarPanelHeight("worktree")}
|
||||||
|
onkeydown={(event) => onSidebarPanelResizeKeydown(event, "worktree")}
|
||||||
></div>
|
></div>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="left-panel-resize-placeholder" aria-hidden="true"></span>
|
<span class="left-panel-resize-placeholder" aria-hidden="true"></span>
|
||||||
@@ -6241,20 +6202,26 @@
|
|||||||
onDeleteTag={deleteLocalTag}
|
onDeleteTag={deleteLocalTag}
|
||||||
onPushTag={pushLocalTag}
|
onPushTag={pushLocalTag}
|
||||||
/>
|
/>
|
||||||
{#if !tagsPanelCollapsed}
|
{#if sidebarHandleVisible("tags", branchPanelCollapsed, worktreePanelCollapsed, tagsPanelCollapsed, stashPanelCollapsed, explorerPanelCollapsed)}
|
||||||
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
||||||
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
||||||
<div
|
<div
|
||||||
class="panel-resize-handle left-panel-resize-handle tags-panel-resize-handle"
|
class="panel-resize-handle left-panel-resize-handle"
|
||||||
class:resizing={resizingLeftTagsPanel}
|
class:resizing={resizingSidebarPanel === "tags"}
|
||||||
role="separator" aria-orientation="horizontal" aria-label="Resize tags panel height"
|
role="separator"
|
||||||
aria-valuenow={leftTagsPanelHeight} aria-valuemin={80} aria-valuemax={420}
|
aria-orientation="horizontal"
|
||||||
|
aria-label="Resize tags panel height"
|
||||||
|
aria-valuenow={sidebarPanelHeights.tags}
|
||||||
|
aria-valuemin={SIDEBAR_PANEL_MIN_HEIGHT.tags}
|
||||||
|
aria-valuemax={SIDEBAR_PANEL_MAX_HEIGHT}
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
onpointerdown={startLeftTagsPanelResize}
|
title="Drag to move the border · double-click to reset"
|
||||||
onpointermove={onLeftTagsPanelResizeMove}
|
onpointerdown={(event) => startSidebarPanelResize(event, "tags")}
|
||||||
onpointerup={endLeftTagsPanelResize}
|
onpointermove={onSidebarPanelResizeMove}
|
||||||
onpointercancel={endLeftTagsPanelResize}
|
onpointerup={endSidebarPanelResize}
|
||||||
onkeydown={onLeftTagsPanelResizeKeydown}
|
onpointercancel={endSidebarPanelResize}
|
||||||
|
ondblclick={() => resetSidebarPanelHeight("tags")}
|
||||||
|
onkeydown={(event) => onSidebarPanelResizeKeydown(event, "tags")}
|
||||||
></div>
|
></div>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="left-panel-resize-placeholder" aria-hidden="true"></span>
|
<span class="left-panel-resize-placeholder" aria-hidden="true"></span>
|
||||||
@@ -6271,24 +6238,26 @@
|
|||||||
collapsed={stashPanelCollapsed}
|
collapsed={stashPanelCollapsed}
|
||||||
onToggleCollapsed={toggleStashPanelCollapsed}
|
onToggleCollapsed={toggleStashPanelCollapsed}
|
||||||
/>
|
/>
|
||||||
{#if !explorerPanelCollapsed && !stashPanelCollapsed}
|
{#if sidebarHandleVisible("stash", branchPanelCollapsed, worktreePanelCollapsed, tagsPanelCollapsed, stashPanelCollapsed, explorerPanelCollapsed)}
|
||||||
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
||||||
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
||||||
<div
|
<div
|
||||||
class="panel-resize-handle left-panel-resize-handle stash-panel-resize-handle"
|
class="panel-resize-handle left-panel-resize-handle"
|
||||||
class:resizing={resizingLeftStashPanel}
|
class:resizing={resizingSidebarPanel === "stash"}
|
||||||
role="separator"
|
role="separator"
|
||||||
aria-orientation="horizontal"
|
aria-orientation="horizontal"
|
||||||
aria-label={stashPanelCollapsed ? "Resize files panel space" : "Resize stash and explorer panels"}
|
aria-label="Resize stashes panel height"
|
||||||
aria-valuenow={stashPanelCollapsed ? leftBranchPanelHeight : leftStashPanelHeight}
|
aria-valuenow={sidebarPanelHeights.stash}
|
||||||
aria-valuemin={stashPanelCollapsed ? LEFT_BRANCH_PANEL_MIN_HEIGHT : LEFT_STASH_PANEL_MIN_HEIGHT}
|
aria-valuemin={SIDEBAR_PANEL_MIN_HEIGHT.stash}
|
||||||
aria-valuemax={stashPanelCollapsed ? LEFT_BRANCH_PANEL_MAX_HEIGHT : LEFT_STASH_PANEL_MAX_HEIGHT}
|
aria-valuemax={SIDEBAR_PANEL_MAX_HEIGHT}
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
onpointerdown={startLeftStashPanelResize}
|
title="Drag to move the border · double-click to reset"
|
||||||
onpointermove={onLeftStashPanelResizeMove}
|
onpointerdown={(event) => startSidebarPanelResize(event, "stash")}
|
||||||
onpointerup={endLeftStashPanelResize}
|
onpointermove={onSidebarPanelResizeMove}
|
||||||
onpointercancel={endLeftStashPanelResize}
|
onpointerup={endSidebarPanelResize}
|
||||||
onkeydown={onLeftStashPanelResizeKeydown}
|
onpointercancel={endSidebarPanelResize}
|
||||||
|
ondblclick={() => resetSidebarPanelHeight("stash")}
|
||||||
|
onkeydown={(event) => onSidebarPanelResizeKeydown(event, "stash")}
|
||||||
></div>
|
></div>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="left-panel-resize-placeholder" aria-hidden="true"></span>
|
<span class="left-panel-resize-placeholder" aria-hidden="true"></span>
|
||||||
|
|||||||
+9
-80
@@ -1713,16 +1713,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.left-sidebar {
|
.left-sidebar {
|
||||||
|
/* The row template is built in App.svelte from the panel heights. */
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: minmax(180px, var(--branch-panel-height, 260px)) 14px minmax(150px, var(--stash-panel-height, 190px)) 14px minmax(220px, 1fr);
|
|
||||||
align-content: start;
|
align-content: start;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
gap: 0;
|
gap: 0;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-panel-resize-handle {
|
.left-panel-resize-handle {
|
||||||
min-height: 14px;
|
min-height: 8px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1732,34 +1734,12 @@
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-sidebar.branch-collapsed {
|
|
||||||
grid-template-rows: auto 0 minmax(150px, var(--stash-panel-height, 190px)) 14px minmax(220px, 1fr);
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-sidebar.explorer-collapsed {
|
|
||||||
grid-template-rows: minmax(180px, var(--branch-panel-height, 260px)) 14px minmax(150px, var(--stash-panel-height, 190px)) 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-sidebar.branch-collapsed.explorer-collapsed {
|
|
||||||
grid-template-rows: auto 0 minmax(150px, var(--stash-panel-height, 190px)) 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-sidebar:has(.stash-panel.collapsed) {
|
|
||||||
grid-template-rows: minmax(180px, var(--branch-panel-height, 260px)) 14px auto 0 minmax(220px, 1fr);
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-sidebar.branch-collapsed:has(.stash-panel.collapsed) {
|
|
||||||
grid-template-rows: auto 0 auto 0 minmax(220px, 1fr);
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-sidebar.explorer-collapsed:has(.stash-panel.collapsed) {
|
|
||||||
grid-template-rows: minmax(180px, var(--branch-panel-height, 260px)) 14px auto 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-sidebar.branch-collapsed.explorer-collapsed:has(.stash-panel.collapsed) {
|
|
||||||
grid-template-rows: auto 0 auto 0 auto;
|
|
||||||
align-content: start;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --- Main panel --- */
|
/* --- Main panel --- */
|
||||||
|
|
||||||
@@ -7508,31 +7488,6 @@ input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in s
|
|||||||
.history-aside { grid-template-columns: 1fr; grid-template-rows: minmax(0, 1fr); row-gap: 0; }
|
.history-aside { grid-template-columns: 1fr; grid-template-rows: minmax(0, 1fr); row-gap: 0; }
|
||||||
.history-resize-handle { display: none; }
|
.history-resize-handle { display: none; }
|
||||||
.shell-body { gap: 6px; }
|
.shell-body { gap: 6px; }
|
||||||
.left-sidebar {
|
|
||||||
grid-template-rows: minmax(180px, var(--branch-panel-height, 230px)) 14px minmax(150px, var(--stash-panel-height, 170px)) 14px minmax(220px, 1fr);
|
|
||||||
}
|
|
||||||
.left-sidebar:has(.stash-panel.collapsed) {
|
|
||||||
grid-template-rows: minmax(180px, var(--branch-panel-height, 230px)) 14px auto 0 minmax(220px, 1fr);
|
|
||||||
}
|
|
||||||
.left-sidebar.branch-collapsed {
|
|
||||||
grid-template-rows: auto 0 minmax(150px, var(--stash-panel-height, 170px)) 14px minmax(220px, 1fr);
|
|
||||||
}
|
|
||||||
.left-sidebar.explorer-collapsed {
|
|
||||||
grid-template-rows: minmax(180px, var(--branch-panel-height, 230px)) 14px minmax(150px, var(--stash-panel-height, 170px)) 0 auto;
|
|
||||||
}
|
|
||||||
.left-sidebar.branch-collapsed:has(.stash-panel.collapsed) {
|
|
||||||
grid-template-rows: auto 0 auto 0 minmax(220px, 1fr);
|
|
||||||
}
|
|
||||||
.left-sidebar.explorer-collapsed:has(.stash-panel.collapsed) {
|
|
||||||
grid-template-rows: minmax(180px, var(--branch-panel-height, 230px)) 14px auto 0 auto;
|
|
||||||
}
|
|
||||||
.left-sidebar.branch-collapsed.explorer-collapsed {
|
|
||||||
grid-template-rows: auto 0 minmax(150px, var(--stash-panel-height, 170px)) 0 auto;
|
|
||||||
}
|
|
||||||
.left-sidebar.branch-collapsed.explorer-collapsed:has(.stash-panel.collapsed) {
|
|
||||||
grid-template-rows: auto 0 auto 0 auto;
|
|
||||||
align-content: start;
|
|
||||||
}
|
|
||||||
.section-head { min-height: 40px; padding: 6px 10px; }
|
.section-head { min-height: 40px; padding: 6px 10px; }
|
||||||
.repo-summary { height: 40px; padding: 0 10px; }
|
.repo-summary { height: 40px; padding: 0 10px; }
|
||||||
.repo-branch { max-width: 160px; }
|
.repo-branch { max-width: 160px; }
|
||||||
@@ -7562,32 +7517,6 @@ input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in s
|
|||||||
.file-history-dialog-row time { display: none; }
|
.file-history-dialog-row time { display: none; }
|
||||||
.file-history-dialog-actions { display: grid; }
|
.file-history-dialog-actions { display: grid; }
|
||||||
.file-history-dialog-actions button { width: 32px; min-width: 32px; padding: 0; overflow: hidden; color: var(--color-ink-muted); font-size: 0; gap: 0; }
|
.file-history-dialog-actions button { width: 32px; min-width: 32px; padding: 0; overflow: hidden; color: var(--color-ink-muted); font-size: 0; gap: 0; }
|
||||||
.left-sidebar {
|
|
||||||
grid-template-rows: minmax(180px, var(--branch-panel-height, 240px)) 14px minmax(150px, var(--stash-panel-height, 180px)) 14px minmax(220px, 1fr);
|
|
||||||
min-height: 560px;
|
|
||||||
}
|
|
||||||
.left-sidebar:has(.stash-panel.collapsed) {
|
|
||||||
grid-template-rows: minmax(180px, var(--branch-panel-height, 240px)) 14px auto 0 minmax(220px, 1fr);
|
|
||||||
}
|
|
||||||
.left-sidebar.branch-collapsed {
|
|
||||||
grid-template-rows: auto 0 minmax(150px, var(--stash-panel-height, 180px)) 14px minmax(220px, 1fr);
|
|
||||||
}
|
|
||||||
.left-sidebar.explorer-collapsed {
|
|
||||||
grid-template-rows: minmax(120px, var(--branch-panel-height, 240px)) 14px minmax(150px, var(--stash-panel-height, 180px)) 0 auto;
|
|
||||||
}
|
|
||||||
.left-sidebar.branch-collapsed:has(.stash-panel.collapsed) {
|
|
||||||
grid-template-rows: auto 0 auto 0 minmax(0, 1fr);
|
|
||||||
}
|
|
||||||
.left-sidebar.explorer-collapsed:has(.stash-panel.collapsed) {
|
|
||||||
grid-template-rows: minmax(120px, var(--branch-panel-height, 240px)) 14px auto 0 auto;
|
|
||||||
}
|
|
||||||
.left-sidebar.branch-collapsed.explorer-collapsed {
|
|
||||||
grid-template-rows: auto 0 minmax(150px, var(--stash-panel-height, 180px)) 0 auto;
|
|
||||||
}
|
|
||||||
.left-sidebar.branch-collapsed.explorer-collapsed:has(.stash-panel.collapsed) {
|
|
||||||
grid-template-rows: auto 0 auto 0 auto;
|
|
||||||
align-content: start;
|
|
||||||
}
|
|
||||||
.top-section { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) 14px var(--commit-panel-height, 190px); }
|
.top-section { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) 14px var(--commit-panel-height, 190px); }
|
||||||
.repo-form { grid-template-columns: 1fr; }
|
.repo-form { grid-template-columns: 1fr; }
|
||||||
.repo-tabbar { grid-template-columns: auto minmax(0, 1fr) auto; }
|
.repo-tabbar { grid-template-columns: auto minmax(0, 1fr) auto; }
|
||||||
@@ -9172,6 +9101,10 @@ section > header.page-header.page-header {
|
|||||||
|
|
||||||
/* Compact accordion navigation (layout A). */
|
/* Compact accordion navigation (layout A). */
|
||||||
.left-sidebar { overflow-y: auto; overflow-x: hidden; }
|
.left-sidebar { overflow-y: auto; overflow-x: hidden; }
|
||||||
|
/* While a border is being dragged, keep the cursor and stop text selection. */
|
||||||
|
.left-sidebar.resizing-panels { cursor: row-resize; user-select: none; }
|
||||||
|
.left-sidebar.resizing-panels * { pointer-events: none; }
|
||||||
|
.left-sidebar.resizing-panels .panel-resize-handle { pointer-events: auto; }
|
||||||
.left-sidebar > .panel { min-width: 0; }
|
.left-sidebar > .panel { min-width: 0; }
|
||||||
.left-sidebar .section-head {
|
.left-sidebar .section-head {
|
||||||
display: flex; align-items: center; justify-content: space-between; gap: 6px;
|
display: flex; align-items: center; justify-content: space-between; gap: 6px;
|
||||||
@@ -9193,7 +9126,7 @@ section > header.page-header.page-header {
|
|||||||
.left-sidebar :is(.branch-create-toggle, .stash-toggle, .explorer-bulk-button):hover:not(:disabled) {
|
.left-sidebar :is(.branch-create-toggle, .stash-toggle, .explorer-bulk-button):hover:not(:disabled) {
|
||||||
background: var(--color-surface-hover); color: var(--color-ink);
|
background: var(--color-surface-hover); color: var(--color-ink);
|
||||||
}
|
}
|
||||||
.left-sidebar .left-panel-resize-handle { min-height: 6px; }
|
.left-sidebar .left-panel-resize-handle { min-height: 8px; }
|
||||||
.left-sidebar .branch-list, .left-sidebar .explorer-list { padding: 4px 0; }
|
.left-sidebar .branch-list, .left-sidebar .explorer-list { padding: 4px 0; }
|
||||||
.left-sidebar .branch-group-toggle {
|
.left-sidebar .branch-group-toggle {
|
||||||
min-height: 30px; padding: 5px 10px; border-radius: 0;
|
min-height: 30px; padding: 5px 10px; border-radius: 0;
|
||||||
@@ -9215,8 +9148,6 @@ section > header.page-header.page-header {
|
|||||||
.left-sidebar .stash-input { grid-column: 1 / -1; }
|
.left-sidebar .stash-input { grid-column: 1 / -1; }
|
||||||
.left-sidebar .explorer-tool-action, .left-sidebar .explorer-action-divider { display: none; }
|
.left-sidebar .explorer-tool-action, .left-sidebar .explorer-action-divider { display: none; }
|
||||||
/* File actions remain available through the file context menu. */
|
/* File actions remain available through the file context menu. */
|
||||||
.left-sidebar .worktree-panel { display: grid; grid-template-rows: 42px minmax(0, 1fr); min-height: 0; overflow: hidden; }
|
|
||||||
.left-sidebar .worktree-panel.collapsed { grid-template-rows: 42px; }
|
|
||||||
.sidebar-worktree-list { min-height: 0; overflow: auto; padding: 4px 0; }
|
.sidebar-worktree-list { min-height: 0; overflow: auto; padding: 4px 0; }
|
||||||
.sidebar-worktree-row {
|
.sidebar-worktree-row {
|
||||||
display: flex; align-items: center; gap: 8px; width: 100%; min-height: 46px;
|
display: flex; align-items: center; gap: 8px; width: 100%; min-height: 46px;
|
||||||
@@ -9244,8 +9175,6 @@ section > header.page-header.page-header {
|
|||||||
.left-sidebar .section-head button svg { width: 14px; height: 14px; stroke-width: 1.75; }
|
.left-sidebar .section-head button svg { width: 14px; height: 14px; stroke-width: 1.75; }
|
||||||
.left-sidebar .section-head .pill-count { min-width: 24px; justify-content: center; }
|
.left-sidebar .section-head .pill-count { min-width: 24px; justify-content: center; }
|
||||||
|
|
||||||
.left-sidebar .tags-panel { display: grid; grid-template-rows: 42px minmax(0, 1fr); min-height: 0; overflow: hidden; }
|
|
||||||
.left-sidebar .tags-panel.collapsed { grid-template-rows: 42px; }
|
|
||||||
.sidebar-tags-list { min-height: 0; overflow: auto; padding: 4px 0; }
|
.sidebar-tags-list { min-height: 0; overflow: auto; padding: 4px 0; }
|
||||||
.left-sidebar .tags-panel .tag-create-form { grid-template-columns: auto minmax(0, 1fr) auto auto; margin: 4px 8px; }
|
.left-sidebar .tags-panel .tag-create-form { grid-template-columns: auto minmax(0, 1fr) auto auto; margin: 4px 8px; }
|
||||||
.left-sidebar .tags-panel .tag-create-form input[aria-label="Tag message"] { grid-column: 2 / -1; grid-row: 2; }
|
.left-sidebar .tags-panel .tag-create-form input[aria-label="Tag message"] { grid-column: 2 / -1; grid-row: 2; }
|
||||||
|
|||||||
Reference in New Issue
Block a user