Skip to content

Commit f1e7590

Browse files
committed
Auto-flip compare panel orientation based on width
Uses a ResizeObserver to prefer horizontal layout when the panel is wide enough (≥600px) and vertical when narrow, automatically updating the pinned compare panel orientation on resize. (#5171, #5253)
1 parent 2c8c7d2 commit f1e7590

1 file changed

Lines changed: 44 additions & 17 deletions

File tree

src/webviews/apps/plus/graph/components/gl-graph-details-panel.ts

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ declare global {
9191
}
9292
}
9393

94+
type PanelOrientation = 'horizontal' | 'vertical';
95+
9496
@customElement('gl-graph-details-panel')
9597
export class GlGraphDetailsPanel extends SignalWatcher(LitElement) {
9698
@consume({ context: graphServicesContext, subscribe: true })
@@ -440,9 +442,22 @@ export class GlGraphDetailsPanel extends SignalWatcher(LitElement) {
440442
return this;
441443
}
442444

445+
private _resizeObserver?: ResizeObserver;
446+
@state() private _preferredCompareOrientation: PanelOrientation = 'vertical';
447+
443448
override connectedCallback(): void {
444449
super.connectedCallback?.();
445450
this.addEventListener('switch-model', this.handleSwitchModel);
451+
this._preferredCompareOrientation = this.clientWidth >= 600 ? 'horizontal' : 'vertical';
452+
this._resizeObserver = new ResizeObserver(entries => {
453+
const preferred: PanelOrientation =
454+
(entries[0]?.contentRect.width ?? this.clientWidth) >= 600 ? 'horizontal' : 'vertical';
455+
if (this._preferredCompareOrientation !== preferred) {
456+
this._preferredCompareOrientation = preferred;
457+
this.autoFlipCompareOrientation();
458+
}
459+
});
460+
this._resizeObserver.observe(this);
446461
}
447462

448463
private handleSwitchModel = (): void => {
@@ -518,6 +533,8 @@ export class GlGraphDetailsPanel extends SignalWatcher(LitElement) {
518533
override disconnectedCallback(): void {
519534
super.disconnectedCallback?.();
520535
this.removeEventListener('switch-model', this.handleSwitchModel);
536+
this._resizeObserver?.disconnect();
537+
this._resizeObserver = undefined;
521538
clearTimeout(this._suppressContentOverflowTimer);
522539
this._suppressContentOverflowTimer = undefined;
523540
clearTimeout(this._suppressModePanelOverflowTimer);
@@ -1014,19 +1031,19 @@ export class GlGraphDetailsPanel extends SignalWatcher(LitElement) {
10141031

10151032
const compareSheet = compareSheetOpen
10161033
? (() => {
1017-
// Sheet → pinned panel: default click always moves to beside (horizontal),
1018-
// Alt-click moves to below (vertical). Icon + tooltip preview the live action
1019-
// based on the alt-key state so the affordance reads correctly mid-press.
1020-
const labelFor = (o: 'horizontal' | 'vertical') =>
1021-
o === 'horizontal' ? 'Move Beside' : 'Move Below';
1022-
const iconFor = (o: 'horizontal' | 'vertical') =>
1034+
// Click pins to preferred orientation; Alt-click flips it.
1035+
// Icon + tooltip update live with the Alt-key so the affordance previews the actual action.
1036+
const labelFor = (o: PanelOrientation) => (o === 'horizontal' ? 'Move Beside' : 'Move Below');
1037+
const iconFor = (o: PanelOrientation) =>
10231038
o === 'horizontal' ? 'layout-sidebar-right' : 'layout-panel';
1024-
const effective: 'horizontal' | 'vertical' = this._modifiers.altKey ? 'vertical' : 'horizontal';
1039+
const preferred = this._preferredCompareOrientation;
1040+
const alternate = this.flipOrientation(preferred);
1041+
const effective = this._modifiers.altKey ? alternate : preferred;
10251042
const actionLabel = labelFor(effective);
10261043
const actionIcon = iconFor(effective);
10271044
const tooltipContent = this._modifiers.altKey
10281045
? actionLabel
1029-
: `${actionLabel}\n[${getAltKeySymbol()}] ${labelFor('vertical')}`;
1046+
: `${actionLabel}\n[${getAltKeySymbol()}] ${labelFor(alternate)}`;
10301047
return html`<gl-detail-sheet
10311048
aria-label="Compare"
10321049
sheet-title="Comparing References"
@@ -1091,23 +1108,33 @@ export class GlGraphDetailsPanel extends SignalWatcher(LitElement) {
10911108
};
10921109

10931110
private handleOpenCompareAsPanel = (e: MouseEvent): void => {
1094-
// Sheet → pinned panel: default click always moves to beside (horizontal); Alt-click
1095-
// moves to below (vertical). The orientation preview in the sheet header tooltip mirrors
1096-
// this so the affordance reads correctly mid-press.
1097-
// Tell the sheet to skip its focus-restoration step on disconnect — the user is
1098-
// transitioning INTO the new pinned panel, not dismissing the sheet, so returning focus
1099-
// to whatever row was focused before the sheet opened is the wrong direction.
1111+
// Skip the sheet's focus-restoration — the user is transitioning INTO the panel,
1112+
// not dismissing the sheet.
11001113
const sheet = this.querySelector('gl-detail-sheet');
11011114
if (sheet != null) {
11021115
(sheet as { skipFocusRestore: boolean }).skipFocusRestore = true;
11031116
}
1104-
const target: 'horizontal' | 'vertical' = e.altKey ? 'vertical' : 'horizontal';
1117+
1118+
const preferred = this._preferredCompareOrientation;
1119+
const target = e.altKey ? this.flipOrientation(preferred) : preferred;
11051120
this._workflow.openCompareAsPanel(target);
11061121
};
11071122

1123+
private flipOrientation(o: PanelOrientation): PanelOrientation {
1124+
return o === 'horizontal' ? 'vertical' : 'horizontal';
1125+
}
1126+
1127+
private autoFlipCompareOrientation(): void {
1128+
if (!this._state.compareAsPanel.get()) return;
1129+
1130+
const preferred = this._preferredCompareOrientation;
1131+
if (this._state.compareSplitOrientation.get() !== preferred) {
1132+
this._state.compareSplitOrientation.set(preferred);
1133+
}
1134+
}
1135+
11081136
private handleFlipCompareOrientation = (): void => {
1109-
const current = this._state.compareSplitOrientation.get();
1110-
this._state.compareSplitOrientation.set(current === 'horizontal' ? 'vertical' : 'horizontal');
1137+
this._state.compareSplitOrientation.set(this.flipOrientation(this._state.compareSplitOrientation.get()));
11111138
};
11121139

11131140
private handleCompareSplitChange = (e: CustomEvent<{ position: number }>): void => {

0 commit comments

Comments
 (0)