diff --git a/src/shared/versions.js b/src/shared/versions.js index 636596b..0a0fb74 100644 --- a/src/shared/versions.js +++ b/src/shared/versions.js @@ -1,6 +1,6 @@ export const HARBOR_VERSIONS = Object.freeze({ - macClient: '0.8.7', - gatewayClient: '0.8.7', + macClient: '0.8.8', + gatewayClient: '0.8.8', gatewayBackend: '0.8.0', }); diff --git a/src/web/components/ServerPicker.jsx b/src/web/components/ServerPicker.jsx index 6910f89..476fd92 100644 --- a/src/web/components/ServerPicker.jsx +++ b/src/web/components/ServerPicker.jsx @@ -59,16 +59,16 @@ function ServerHealth({ ping, fallback }) { function ServerCheckButton({ checking, disabled, onClick }) { return ; } diff --git a/src/web/styles.css b/src/web/styles.css index b1dd178..ae22edc 100644 --- a/src/web/styles.css +++ b/src/web/styles.css @@ -2597,7 +2597,7 @@ p { .client-server-grid { display: grid; grid-template-columns: 1fr; - gap: 8px; + gap: 0; width: min(100%, 220px); margin-inline: auto; } @@ -2607,14 +2607,15 @@ p { display: grid; grid-template-columns: minmax(0, 1fr) 120px minmax(0, 1fr); align-items: center; + margin-inline: auto; } .client-server { min-width: 0; min-height: 44px; display: grid; - place-items: center; - padding: 6px 4px 7px; + place-items: end center; + padding: 0 4px 4px; border: 0; border-bottom: 1px solid var(--client-border); border-radius: 0; @@ -2686,9 +2687,21 @@ p { .client-server-health { display: grid; place-items: center; + color: var(--client-muted); + font-size: 9px; + font-variant-numeric: tabular-nums; + line-height: 1.2; white-space: nowrap; } +.client-server-meta .client-server-health { + width: 42px; + min-height: 44px; + place-items: end center; + padding-bottom: 4px; + border-bottom: 1px solid var(--client-accent); +} + .client-server-health > span { grid-area: 1 / 1; transition: opacity 420ms ease, filter 520ms cubic-bezier(0.16, 1, 0.3, 1), color 520ms ease; @@ -2718,8 +2731,8 @@ p { .client-server-tools { display: grid; - gap: 9px; - margin-bottom: 14px; + gap: 6px; + margin-bottom: 6px; } .client-server-toolbar { @@ -2766,7 +2779,7 @@ p { grid-column: 3; grid-row: 1; justify-self: start; - width: 104px; + width: 32px; height: 32px; min-height: 32px; padding: 0; @@ -2776,15 +2789,13 @@ p { display: flex; align-items: center; justify-content: center; - gap: 5px; - font: 700 9px/1.2 'JetBrains Mono', 'SF Mono', ui-monospace, Menlo, monospace; cursor: pointer; transition: color 300ms ease, opacity 300ms ease, text-shadow 500ms ease; } .client-server-check svg { - width: 14px; - height: 14px; + width: 16px; + height: 16px; fill: none; stroke: currentColor; stroke-width: 1.6; @@ -2960,16 +2971,18 @@ p { .client-server-pinned { display: grid; - gap: 7px; - margin-bottom: 10px; + gap: 3px; + margin-bottom: 6px; } .client-server-auto { + width: 220px; min-height: 44px; display: grid; place-items: center; - gap: 3px; - padding: 6px; + gap: 1px; + margin-inline: auto; + padding: 3px 6px 7px; border: 0; border-bottom: 1px solid var(--client-border); background: transparent; @@ -3034,16 +3047,18 @@ p { } .client-servers.is-scalable .client-server-grid { - gap: 5px; + gap: 0; } .client-server-meta { + position: relative; grid-column: 3; justify-self: start; - display: flex; - align-items: center; - gap: 4px; - margin-left: 10px; + width: 42px; + min-height: 44px; + display: grid; + place-items: center; + margin-left: 8px; } .client-server-row .client-server { @@ -3052,17 +3067,24 @@ p { } .client-server-favorite { - width: 28px; + position: absolute; + top: 50%; + left: calc(100% + 2px); + width: 44px; height: 44px; padding: 0; border: 0; background: transparent; color: var(--client-border); + font-size: 10px; cursor: pointer; + opacity: 0.45; + transform: translateY(-50%); } .client-server-favorite.is-active { color: var(--client-accent); + opacity: 1; } .client-server-empty { @@ -3463,7 +3485,7 @@ p { } .client-form-content { - gap: 32px; + gap: 24px; } .harbor-brand { @@ -3494,7 +3516,7 @@ p { } .client-server-check { - width: 104px; + width: 44px; height: 44px; } @@ -3506,10 +3528,6 @@ p { grid-template-rows: 44px; } - .client-server-favorite { - width: 44px; - } - .client-local-rule { grid-template-columns: 44px minmax(0, 1fr) 44px; } diff --git a/test/web/responsive-layout-contract.test.js b/test/web/responsive-layout-contract.test.js index b1ace63..9598a66 100644 --- a/test/web/responsive-layout-contract.test.js +++ b/test/web/responsive-layout-contract.test.js @@ -63,7 +63,8 @@ test('tablet and mobile regions use normal flow with viewport-safe widths', () = assert.match(rule('.client-duration-toggle'), /width:\s*min\(290px, 100%\)/); assert.match(mobile, /\.client-server-toolbar \{[\s\S]*grid-template-rows:\s*44px 44px/); - assert.match(mobile, /\.client-server-check \{[\s\S]*width:\s*104px/); + assert.match(mobile, /\.client-form-content \{[\s\S]*gap:\s*24px/); + assert.match(mobile, /\.client-server-check \{[\s\S]*width:\s*44px/); assert.match(styles, /\.client-instructions\s*\{[\s\S]*width:\s*min\(470px, 100vw\)/); assert.match(styles, /\.client-local-rules\s*\{[\s\S]*width:\s*min\(480px, 100vw\)/); assert.match(styles, /\.client-confirmation-dialog\s*\{[\s\S]*width:\s*min\(430px, calc\(100vw - 48px\)\)/); diff --git a/test/web/server-picker.test.js b/test/web/server-picker.test.js index d19ba17..10548ff 100644 --- a/test/web/server-picker.test.js +++ b/test/web/server-picker.test.js @@ -57,12 +57,16 @@ test('manual ping uses plain language and keeps results beside server names', () assert.match(picker, /function ServerHealth/); assert.match(picker, /client-server-health-checking/); assert.match(picker, /function ServerCheckButton/); - assert.match(picker, /\{checking \? 'Проверяем' : 'Проверить пинг'\}<\/span>/); + assert.match(picker, /client-server-check client-tooltip-anchor/); + assert.match(picker, //); assert.doesNotMatch(picker, /TCP|Не проверен/); assert.match(picker, /\{server\.label\}<\/strong>[\s\S]*?<\/button>[\s\S]*?client-server-meta/); assert.match(styles, /\.client-server-row \{[\s\S]*?grid-template-columns: minmax\(0, 1fr\) 120px minmax\(0, 1fr\);/); assert.match(styles, /\.client-server-row \.client-server \{[\s\S]*?width: 120px;/); - assert.match(styles, /\.client-server-meta \{[\s\S]*?grid-column: 3;[\s\S]*?margin-left: 10px;/); + assert.match(styles, /\.client-server-health \{[\s\S]*?font-size: 9px;[\s\S]*?font-variant-numeric: tabular-nums;/); + assert.match(styles, /\.client-server-meta \.client-server-health \{[\s\S]*?padding-bottom: 4px;[\s\S]*?border-bottom: 1px solid var\(--client-accent\);/); + assert.match(styles, /\.client-server-meta \{[\s\S]*?width: 42px;[\s\S]*?margin-left: 8px;/); + assert.match(styles, /\.client-server-favorite \{[\s\S]*?position: absolute;[\s\S]*?width: 44px;/); assert.match(picker, /server={servers\[0\]}[\s\S]*?ping={pings\[servers\[0\]\.id\]}/); assert.match(picker, /simpleServers\.map[\s\S]*?ping={pings\[server\.id\]}/); }); @@ -77,6 +81,7 @@ test('server picker starts simple and reveals advanced controls on demand', () = assert.match(styles, /\.client-servers\.is-scalable \{[\s\S]*?width: min\(100%, 300px\);/); assert.match(styles, /\.client-server-mode-toggle \{[\s\S]*?grid-row: 2;/); assert.match(styles, /\.client-server-check \{[\s\S]*?grid-column: 3;[\s\S]*?grid-row: 1;/); + assert.match(styles, /\.client-server-auto \{[\s\S]*?width: 220px;[\s\S]*?margin-inline: auto;/); assert.match(picker, /client-server-mode-panel is-simple/); assert.match(picker, /client-server-mode-panel is-advanced/); assert.match(picker, /inert={advanced \? true : undefined}/);