Keep edge mode to the desktop shell and mirror it in right-to-left

Phones and Cockpit keep their own layouts and do not show the switch. The
rails' name panels and edge mode run toward the middle in a right-to-left
language, and the switch reads its side again after the layout moves it.

Co-authored-by: Manjunath Paparaju <[email protected]>
This commit is contained in:
Sameh KhamisandManjunath Paparaju committed 2026-11-14 13:41:07 -08:00
1 parent 9374e0228b
commit d0b614d88e
4 files changed
+88 -15

No files matched your search

+13 -4
View File
@@ -15,10 +15,19 @@ function toggle() {
function sync() {
side.value = panelSide(button.value);
}
onMounted(sync);
const icon = computed(() => (side.value === 'right' ? 'align_horizontal_right' : 'align_horizontal_left'));
// The layout moves some panels to the right column after they mount, so the
// side is read again once that has happened.
onMounted(() => {
sync();
globalThis.requestAnimationFrame?.(sync);
});
const icon = computed(() =>
side.value === 'right' ? 'align_horizontal_right' : 'align_horizontal_left',
);
const label = computed(() =>
on.value ? t('Move panels back beside the rail') : t('Move panels over the rail, to the edge'),
on.value
? t('Move panels back beside the rail')
: t('Move panels over the rail, to the edge'),
);
</script>
@@ -26,7 +35,7 @@ const label = computed(() =>
<button
ref="button"
type="button"
class="ui-panel-edge"
class="ui-panel-edge panel-edge-btn"
:aria-pressed="String(on)"
:aria-label="label"
:title="label"
+3 -1
View File
@@ -26,7 +26,9 @@ apply();
/** Which side a panel element sits on, from the column it is in. */
export function panelSide(element) {
return element?.closest?.('#right-context-rail, #cockpit-utility-controls') ? 'right' : 'left';
return element?.closest?.('#right-context-rail, #cockpit-utility-controls')
? 'right'
: 'left';
}
export function togglePanelEdge(side) {
+28 -10
View File
@@ -37,18 +37,23 @@
}
/* Right: open panels move right by the rail's width and sit over it. */
body.panels-edge-right:not(.context-docked) #right-context-rail > :not(.gev-panel-rail) {
body.panels-edge-right:not(.mobile-shell):not(.cockpit-mode)
#right-context-rail
> :not(.gev-panel-rail) {
z-index: 2;
transform: translateX(var(--panel-rail-clearance, 48px));
}
/* Left: the same, moving left. */
body.panels-edge-left #left-panel-stack > :not(.gev-panel-rail) {
body.panels-edge-left:not(.mobile-shell):not(.cockpit-mode)
#left-panel-stack
> :not(.gev-panel-rail) {
z-index: 2;
transform: translateX(calc(-1 * var(--panel-rail-clearance, 48px)));
}
body.mobile-shell .ui-panel-edge {
body.mobile-shell .ui-panel-edge,
body.cockpit-mode .ui-panel-edge {
display: none;
}
@@ -58,25 +63,38 @@ body.mobile-shell .ui-panel-edge {
--edge-rail-row: 50px;
}
body.panels-edge-left .gev-panel-rail--left:has(.ui-rail--collapsible:not(.ui-rail--expanded)),
body.panels-edge-right:not(.context-docked) .gev-panel-rail--right:has(.ui-rail--collapsible:not(.ui-rail--expanded)) {
body.panels-edge-left:not(.mobile-shell):not(.cockpit-mode)
.gev-panel-rail--left:has(.ui-rail--collapsible:not(.ui-rail--expanded)),
body.panels-edge-right:not(.mobile-shell):not(.cockpit-mode)
.gev-panel-rail--right:has(.ui-rail--collapsible:not(.ui-rail--expanded)) {
top: 0 !important;
z-index: 3;
}
body.panels-edge-left .gev-panel-rail--left .ui-rail--collapsible:not(.ui-rail--expanded),
body.panels-edge-right:not(.context-docked) .gev-panel-rail--right .ui-rail--collapsible:not(.ui-rail--expanded) {
body.panels-edge-left:not(.mobile-shell):not(.cockpit-mode)
.gev-panel-rail--left
.ui-rail--collapsible:not(.ui-rail--expanded),
body.panels-edge-right:not(.mobile-shell):not(.cockpit-mode)
.gev-panel-rail--right
.ui-rail--collapsible:not(.ui-rail--expanded) {
flex-direction: row;
width: max-content;
gap: 4px;
}
body.panels-edge-left #left-panel-stack > :not(.gev-panel-rail):not(.collapsed) {
transform: translate(calc(-1 * var(--panel-rail-clearance, 48px)), var(--edge-rail-row));
body.panels-edge-left:not(.mobile-shell):not(.cockpit-mode)
#left-panel-stack
> :not(.gev-panel-rail):not(.collapsed) {
transform: translate(
calc(-1 * var(--panel-rail-clearance, 48px)),
var(--edge-rail-row)
);
max-height: calc(100% - var(--edge-rail-row)) !important;
}
body.panels-edge-right:not(.context-docked) #right-context-rail > :not(.gev-panel-rail) {
body.panels-edge-right:not(.mobile-shell):not(.cockpit-mode)
#right-context-rail
> :not(.gev-panel-rail):not(.collapsed) {
transform: translate(var(--panel-rail-clearance, 48px), var(--edge-rail-row));
max-height: calc(100% - var(--edge-rail-row)) !important;
}
+44
View File
@@ -242,3 +242,47 @@ html[dir='rtl'] select.gev-field--compact {
html[dir='rtl'] .rail-card-scale {
direction: ltr;
}
/* ── Side rails, mirrored ──────────────────────────────────────────────
The left stack sits on the right edge, so the left rail's name panel
opens to its left and the right rail's to its right, each toward the
middle of the screen, as they do in left-to-right. */
html[dir='rtl'] .gev-panel-rail--left .ui-rail--expanded::after {
right: calc(100% + 6px);
left: auto;
}
html[dir='rtl'] .gev-panel-rail--left .ui-rail--expanded .ui-rail__label {
right: calc(100% + 24px);
left: auto;
}
html[dir='rtl'] .gev-panel-rail--right .ui-rail--expanded::after {
right: auto;
left: calc(100% + 6px);
}
html[dir='rtl'] .gev-panel-rail--right .ui-rail--expanded .ui-rail__label {
right: auto;
left: calc(100% + 24px);
}
/* Panels moved to the screen edge slide over their rail toward that edge. */
html[dir='rtl']
body.panels-edge-left:not(.mobile-shell):not(.cockpit-mode)
#left-panel-stack
> :not(.gev-panel-rail) {
transform: translateX(var(--panel-rail-clearance, 48px));
}
html[dir='rtl']
body.panels-edge-left:not(.mobile-shell):not(.cockpit-mode)
#left-panel-stack
> :not(.gev-panel-rail):not(.collapsed) {
transform: translate(var(--panel-rail-clearance, 48px), var(--edge-rail-row));
}
html[dir='rtl']
body.panels-edge-right:not(.mobile-shell):not(.cockpit-mode)
#right-context-rail
> :not(.gev-panel-rail) {
transform: translate(
calc(-1 * var(--panel-rail-clearance, 48px)),
var(--edge-rail-row)
);
}