diff --git a/src/shared/versions.js b/src/shared/versions.js index 82987ae..b8e0b96 100644 --- a/src/shared/versions.js +++ b/src/shared/versions.js @@ -1,6 +1,6 @@ export const HARBOR_VERSIONS = Object.freeze({ - macClient: '0.8.1', - gatewayClient: '0.8.1', + macClient: '0.8.2', + gatewayClient: '0.8.2', gatewayBackend: '0.8.0', }); diff --git a/src/web/components/ClientOverviewPage.jsx b/src/web/components/ClientOverviewPage.jsx index 50f7a2e..b1b46cf 100644 --- a/src/web/components/ClientOverviewPage.jsx +++ b/src/web/components/ClientOverviewPage.jsx @@ -1068,46 +1068,47 @@ export function ClientOverviewPage({ blocked={gatewayAutoBlocked} onSetGatewayAuto={onSetGatewayAuto} /> - {hasSubscription && subscriptionContentReady && } - {hasSubscription && subscriptionContentReady && } + {hasSubscription && subscriptionContentReady && }
{showPower && (
diff --git a/src/web/styles.css b/src/web/styles.css index aeff5f6..91865ce 100644 --- a/src/web/styles.css +++ b/src/web/styles.css @@ -662,107 +662,21 @@ p { 92% { transform: translateX(-0.75px); } } -.client-instructions-toggle { +.client-secondary-menu { position: fixed; top: 50%; - left: 14px; + right: max(14px, env(safe-area-inset-right)); z-index: 30; - width: 42px; - height: 54px; display: grid; - place-items: center; - padding: 0; - border: 0; - background: transparent; - color: var(--client-muted); - cursor: pointer; + gap: 6px; transform: translateY(-50%); - transition: transform 440ms cubic-bezier(0.16, 1, 0.3, 1); -} - -.client-instructions-toggle svg { - position: relative; - z-index: 1; - width: 23px; - height: 18px; - fill: none; - stroke: currentColor; - stroke-width: 1.7; - stroke-linecap: round; - stroke-linejoin: round; - overflow: visible; - transition: transform 500ms cubic-bezier(0.16, 1, 0.3, 1); -} - -.client-instructions-toggle path { - opacity: 0; - transform: translateX(-5px); - transition: opacity 260ms ease, transform 480ms cubic-bezier(0.16, 1, 0.3, 1); -} - -.client-instructions-toggle path:last-child { - opacity: 1; - transform: translateX(-4px); -} - -.client-instructions-toggle span { - position: absolute; - left: 48px; - width: max-content; - color: var(--client-text); - font: 700 10px/1.2 'JetBrains Mono', 'SF Mono', ui-monospace, Menlo, monospace; - letter-spacing: 0.04em; - opacity: 0; - filter: blur(5px); - pointer-events: none; - transform: translateX(-8px); - transition: opacity 350ms ease, filter 350ms ease, transform 500ms cubic-bezier(0.16, 1, 0.3, 1); -} - -.client-instructions-toggle:hover, -.client-instructions-toggle:focus-visible { - outline: none; - transform: translateY(-50%) translateX(3px); -} - -.client-instructions-toggle:hover path, -.client-instructions-toggle:focus-visible path { - opacity: 1; - transform: translateX(0); -} - -.client-instructions-toggle:hover span, -.client-instructions-toggle:focus-visible span { - opacity: 1; - filter: blur(0); - transform: translateX(0); -} - -.client-instructions-toggle.is-open svg { - transform: rotate(180deg); -} - -.client-instructions-toggle.is-open path { - opacity: 0; -} - -.client-instructions-toggle.is-open path:first-child { - opacity: 1; - transform: translateX(4px); -} - -.client-instructions-toggle.is-open span { - opacity: 0; - visibility: hidden; } +.client-instructions-toggle, .client-local-rules-toggle { - position: fixed; - top: 50%; - right: 14px; - z-index: 30; + position: relative; width: 42px; - height: 54px; + height: 48px; display: grid; place-items: center; padding: 0; @@ -770,10 +684,10 @@ p { background: transparent; color: var(--client-muted); cursor: pointer; - transform: translateY(-50%); transition: color 240ms ease, transform 440ms cubic-bezier(0.16, 1, 0.3, 1); } +.client-instructions-toggle svg, .client-local-rules-toggle svg { width: 23px; height: 23px; @@ -782,9 +696,11 @@ p { stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; + overflow: visible; transition: color 240ms ease, filter 360ms ease, transform 500ms cubic-bezier(0.16, 1, 0.3, 1); } +.client-instructions-toggle span, .client-local-rules-toggle span { position: absolute; right: 48px; @@ -799,18 +715,17 @@ p { transition: opacity 350ms ease, filter 350ms ease, transform 500ms cubic-bezier(0.16, 1, 0.3, 1); } +.client-instructions-toggle:hover, +.client-instructions-toggle:focus-visible, .client-local-rules-toggle:hover, .client-local-rules-toggle:focus-visible { - outline: none; + outline: 0; color: var(--client-accent); - transform: translateY(-50%) translateX(-3px); -} - -.client-local-rules-toggle:hover svg, -.client-local-rules-toggle:focus-visible svg { - filter: drop-shadow(0 0 7px color-mix(in oklch, var(--client-accent) 52%, transparent)); + transform: translateX(-3px); } +.client-instructions-toggle:hover span, +.client-instructions-toggle:focus-visible span, .client-local-rules-toggle:hover span, .client-local-rules-toggle:focus-visible span { opacity: 1; @@ -818,9 +733,19 @@ p { transform: translateX(0); } +.client-instructions-toggle:hover svg, +.client-instructions-toggle:focus-visible svg, +.client-local-rules-toggle:hover svg, +.client-local-rules-toggle:focus-visible svg, +.client-instructions-toggle.is-open svg, +.client-local-rules-toggle.is-open svg { + filter: drop-shadow(0 0 7px color-mix(in oklch, var(--client-accent) 52%, transparent)); +} + .client-local-rules-toggle:disabled { cursor: default; color: var(--client-muted); + transform: none; } .client-local-rules-toggle:disabled span { @@ -829,6 +754,7 @@ p { transform: translateX(0); } +.client-instructions-toggle.is-open, .client-local-rules-toggle.is-open { color: var(--client-accent); } @@ -845,6 +771,7 @@ p { transform: rotate(90deg); } +.client-instructions-toggle.is-open span, .client-local-rules-toggle.is-open span { opacity: 0; visibility: hidden; @@ -1380,16 +1307,16 @@ p { .client-instructions { position: fixed; - inset: 0 auto 0 0; + inset: 0 0 0 auto; z-index: 20; width: min(470px, 100vw); overflow-y: auto; background: color-mix(in oklch, var(--client-bg) 99%, var(--client-panel)); color: var(--client-text); - box-shadow: 26px 0 72px oklch(0.09 0.015 145 / 0.12); + box-shadow: -26px 0 72px oklch(0.09 0.015 145 / 0.12); opacity: 0; visibility: hidden; - transform: translateX(-104%); + transform: translateX(104%); transition: transform 760ms cubic-bezier(0.16, 1, 0.3, 1), opacity 500ms ease, visibility 0s 760ms; } @@ -1403,7 +1330,7 @@ p { .client-instructions-sheet { position: relative; min-height: 100%; - padding: 54px 34px 72px 72px; + padding: 54px 72px 72px 34px; font-family: 'JetBrains Mono', 'SF Mono', ui-monospace, Menlo, monospace; } @@ -3520,11 +3447,7 @@ p { transform: translateX(-50%) scale(1.35); } - .client-instructions-toggle { - left: 8px; - } - - .client-local-rules-toggle { + .client-secondary-menu { right: 8px; } @@ -3572,7 +3495,7 @@ p { } .client-instructions-sheet { - padding: 40px 18px 60px 58px; + padding: 40px 58px 60px 18px; } .client-local-rules-sheet { diff --git a/test/web/responsive-layout-contract.test.js b/test/web/responsive-layout-contract.test.js index 8e1bc86..35c59f1 100644 --- a/test/web/responsive-layout-contract.test.js +++ b/test/web/responsive-layout-contract.test.js @@ -73,6 +73,17 @@ test('tablet and mobile regions use normal flow with viewport-safe widths', () = assert.ok(Math.min(360, desktopOuterColumn) <= desktopOuterColumn, 'details fit the 1440px desktop grid'); }); +test('secondary menus share one right rail and both drawers open from the right', () => { + assert.match(component, /