Raise Harbor versions and move secondary menus to the right rail
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
export const HARBOR_VERSIONS = Object.freeze({
|
export const HARBOR_VERSIONS = Object.freeze({
|
||||||
macClient: '0.8.1',
|
macClient: '0.8.2',
|
||||||
gatewayClient: '0.8.1',
|
gatewayClient: '0.8.2',
|
||||||
gatewayBackend: '0.8.0',
|
gatewayBackend: '0.8.0',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1068,7 +1068,8 @@ export function ClientOverviewPage({
|
|||||||
blocked={gatewayAutoBlocked}
|
blocked={gatewayAutoBlocked}
|
||||||
onSetGatewayAuto={onSetGatewayAuto}
|
onSetGatewayAuto={onSetGatewayAuto}
|
||||||
/>
|
/>
|
||||||
{hasSubscription && subscriptionContentReady && <button
|
{hasSubscription && subscriptionContentReady && <nav className="client-secondary-menu" aria-label="Дополнительные меню">
|
||||||
|
<button
|
||||||
ref={instructionsToggleRef}
|
ref={instructionsToggleRef}
|
||||||
className={`client-instructions-toggle${instructionsOpen ? ' is-open' : ''}`}
|
className={`client-instructions-toggle${instructionsOpen ? ' is-open' : ''}`}
|
||||||
type="button"
|
type="button"
|
||||||
@@ -1081,13 +1082,12 @@ export function ClientOverviewPage({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||||
<path d="m3 5 7 7-7 7" />
|
<circle cx="12" cy="12" r="8.5" />
|
||||||
<path d="m7 5 7 7-7 7" />
|
<path d="M12 11v5M12 8h.01" />
|
||||||
<path d="m11 5 7 7-7 7" />
|
|
||||||
</svg>
|
</svg>
|
||||||
<span>Как использовать</span>
|
<span>Как использовать</span>
|
||||||
</button>}
|
</button>
|
||||||
{hasSubscription && subscriptionContentReady && <button
|
<button
|
||||||
ref={localRulesToggleRef}
|
ref={localRulesToggleRef}
|
||||||
className={`client-local-rules-toggle${localRulesOpen ? ' is-open' : ''}${localRulesPendingRestart ? ' has-pending' : ''}`}
|
className={`client-local-rules-toggle${localRulesOpen ? ' is-open' : ''}${localRulesPendingRestart ? ' has-pending' : ''}`}
|
||||||
type="button"
|
type="button"
|
||||||
@@ -1107,7 +1107,8 @@ export function ClientOverviewPage({
|
|||||||
<span>{gatewayDirect
|
<span>{gatewayDirect
|
||||||
? 'Сейчас работают правила Gateway'
|
? 'Сейчас работают правила Gateway'
|
||||||
: localRulesPendingRestart ? 'Правила ждут перезапуска' : 'Локальные правила'}</span>
|
: localRulesPendingRestart ? 'Правила ждут перезапуска' : 'Локальные правила'}</span>
|
||||||
</button>}
|
</button>
|
||||||
|
</nav>}
|
||||||
<main className={`client-panel${showPower ? '' : ' is-setup'}${hasSubscription ? ' has-subscription' : ''}`}>
|
<main className={`client-panel${showPower ? '' : ' is-setup'}${hasSubscription ? ' has-subscription' : ''}`}>
|
||||||
{showPower && (
|
{showPower && (
|
||||||
<section className="client-power-section" aria-labelledby="connection-title">
|
<section className="client-power-section" aria-labelledby="connection-title">
|
||||||
|
|||||||
@@ -662,107 +662,21 @@ p {
|
|||||||
92% { transform: translateX(-0.75px); }
|
92% { transform: translateX(-0.75px); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-instructions-toggle {
|
.client-secondary-menu {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 14px;
|
right: max(14px, env(safe-area-inset-right));
|
||||||
z-index: 30;
|
z-index: 30;
|
||||||
width: 42px;
|
|
||||||
height: 54px;
|
|
||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
gap: 6px;
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
background: transparent;
|
|
||||||
color: var(--client-muted);
|
|
||||||
cursor: pointer;
|
|
||||||
transform: translateY(-50%);
|
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 {
|
.client-local-rules-toggle {
|
||||||
position: fixed;
|
position: relative;
|
||||||
top: 50%;
|
|
||||||
right: 14px;
|
|
||||||
z-index: 30;
|
|
||||||
width: 42px;
|
width: 42px;
|
||||||
height: 54px;
|
height: 48px;
|
||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -770,10 +684,10 @@ p {
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--client-muted);
|
color: var(--client-muted);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transform: translateY(-50%);
|
|
||||||
transition: color 240ms ease, transform 440ms cubic-bezier(0.16, 1, 0.3, 1);
|
transition: color 240ms ease, transform 440ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.client-instructions-toggle svg,
|
||||||
.client-local-rules-toggle svg {
|
.client-local-rules-toggle svg {
|
||||||
width: 23px;
|
width: 23px;
|
||||||
height: 23px;
|
height: 23px;
|
||||||
@@ -782,9 +696,11 @@ p {
|
|||||||
stroke-width: 1.6;
|
stroke-width: 1.6;
|
||||||
stroke-linecap: round;
|
stroke-linecap: round;
|
||||||
stroke-linejoin: round;
|
stroke-linejoin: round;
|
||||||
|
overflow: visible;
|
||||||
transition: color 240ms ease, filter 360ms ease, transform 500ms cubic-bezier(0.16, 1, 0.3, 1);
|
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 {
|
.client-local-rules-toggle span {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 48px;
|
right: 48px;
|
||||||
@@ -799,18 +715,17 @@ p {
|
|||||||
transition: opacity 350ms ease, filter 350ms ease, transform 500ms cubic-bezier(0.16, 1, 0.3, 1);
|
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:hover,
|
||||||
.client-local-rules-toggle:focus-visible {
|
.client-local-rules-toggle:focus-visible {
|
||||||
outline: none;
|
outline: 0;
|
||||||
color: var(--client-accent);
|
color: var(--client-accent);
|
||||||
transform: translateY(-50%) translateX(-3px);
|
transform: 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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.client-instructions-toggle:hover span,
|
||||||
|
.client-instructions-toggle:focus-visible span,
|
||||||
.client-local-rules-toggle:hover span,
|
.client-local-rules-toggle:hover span,
|
||||||
.client-local-rules-toggle:focus-visible span {
|
.client-local-rules-toggle:focus-visible span {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@@ -818,9 +733,19 @@ p {
|
|||||||
transform: translateX(0);
|
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 {
|
.client-local-rules-toggle:disabled {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
color: var(--client-muted);
|
color: var(--client-muted);
|
||||||
|
transform: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-local-rules-toggle:disabled span {
|
.client-local-rules-toggle:disabled span {
|
||||||
@@ -829,6 +754,7 @@ p {
|
|||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.client-instructions-toggle.is-open,
|
||||||
.client-local-rules-toggle.is-open {
|
.client-local-rules-toggle.is-open {
|
||||||
color: var(--client-accent);
|
color: var(--client-accent);
|
||||||
}
|
}
|
||||||
@@ -845,6 +771,7 @@ p {
|
|||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.client-instructions-toggle.is-open span,
|
||||||
.client-local-rules-toggle.is-open span {
|
.client-local-rules-toggle.is-open span {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
@@ -1380,16 +1307,16 @@ p {
|
|||||||
|
|
||||||
.client-instructions {
|
.client-instructions {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0 auto 0 0;
|
inset: 0 0 0 auto;
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
width: min(470px, 100vw);
|
width: min(470px, 100vw);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
background: color-mix(in oklch, var(--client-bg) 99%, var(--client-panel));
|
background: color-mix(in oklch, var(--client-bg) 99%, var(--client-panel));
|
||||||
color: var(--client-text);
|
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;
|
opacity: 0;
|
||||||
visibility: hidden;
|
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;
|
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 {
|
.client-instructions-sheet {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
padding: 54px 34px 72px 72px;
|
padding: 54px 72px 72px 34px;
|
||||||
font-family: 'JetBrains Mono', 'SF Mono', ui-monospace, Menlo, monospace;
|
font-family: 'JetBrains Mono', 'SF Mono', ui-monospace, Menlo, monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3520,11 +3447,7 @@ p {
|
|||||||
transform: translateX(-50%) scale(1.35);
|
transform: translateX(-50%) scale(1.35);
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-instructions-toggle {
|
.client-secondary-menu {
|
||||||
left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.client-local-rules-toggle {
|
|
||||||
right: 8px;
|
right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3572,7 +3495,7 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.client-instructions-sheet {
|
.client-instructions-sheet {
|
||||||
padding: 40px 18px 60px 58px;
|
padding: 40px 58px 60px 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-local-rules-sheet {
|
.client-local-rules-sheet {
|
||||||
|
|||||||
@@ -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');
|
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, /<nav className="client-secondary-menu" aria-label="Дополнительные меню">/);
|
||||||
|
assert.match(component, /client-instructions-toggle[\s\S]*client-local-rules-toggle/);
|
||||||
|
assert.match(rule('.client-secondary-menu'), /right:\s*max\(14px, env\(safe-area-inset-right\)\)/);
|
||||||
|
assert.match(rule('.client-secondary-menu'), /display:\s*grid/);
|
||||||
|
assert.match(rule('.client-instructions'), /inset:\s*0 0 0 auto/);
|
||||||
|
assert.match(rule('.client-instructions'), /transform:\s*translateX\(104%\)/);
|
||||||
|
assert.match(rule('.client-local-rules'), /inset:\s*0 0 0 auto/);
|
||||||
|
assert.match(rule('.client-local-rules'), /transform:\s*translateX\(104%\)/);
|
||||||
|
});
|
||||||
|
|
||||||
test('responsive motion has a reduced-motion fallback', () => {
|
test('responsive motion has a reduced-motion fallback', () => {
|
||||||
const reducedMotion = /@media \(prefers-reduced-motion: reduce\) \{([\s\S]*)\n\}/.exec(styles)?.[1] || '';
|
const reducedMotion = /@media \(prefers-reduced-motion: reduce\) \{([\s\S]*)\n\}/.exec(styles)?.[1] || '';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user