From 4ed25301db1b284fa894bc51768f65398c344494 Mon Sep 17 00:00:00 2001 From: Dmitriy Petrov Date: Sun, 12 Jul 2026 00:17:17 +0300 Subject: [PATCH] Refine rule delete animation and bump Harbor versions --- src/shared/versions.js | 4 +-- src/web/components/ClientOverviewPage.jsx | 3 +- src/web/styles.css | 39 +++++++++++++++++++---- test/web/rule-editor-contract.test.js | 6 ++-- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/shared/versions.js b/src/shared/versions.js index 35fd898..f26102a 100644 --- a/src/shared/versions.js +++ b/src/shared/versions.js @@ -1,6 +1,6 @@ export const HARBOR_VERSIONS = Object.freeze({ - macClient: '0.6.9', - gatewayClient: '0.6.8', + macClient: '0.6.10', + gatewayClient: '0.6.9', gatewayBackend: '0.6.0', }); diff --git a/src/web/components/ClientOverviewPage.jsx b/src/web/components/ClientOverviewPage.jsx index 612c228..5fcf507 100644 --- a/src/web/components/ClientOverviewPage.jsx +++ b/src/web/components/ClientOverviewPage.jsx @@ -402,7 +402,8 @@ function LocalRulesPanel({ > .client-local-rule-enabled { + z-index: 101; + color: oklch(0.68 0.15 28); +} + .client-local-rule-enabled { width: 24px; height: 32px; @@ -1020,11 +1028,19 @@ p { transition: fill 320ms ease, stroke 260ms ease; } -.client-local-rule-enabled path { +.client-rule-check { stroke-width: 1.8; stroke-dasharray: 12; stroke-dashoffset: 12; - transition: stroke-dashoffset 360ms cubic-bezier(0.16, 1, 0.3, 1); + transition: opacity 160ms ease, stroke-dashoffset 360ms cubic-bezier(0.16, 1, 0.3, 1); +} + +.client-rule-delete-cross { + stroke-width: 1.6; + opacity: 0; + transform: rotate(-35deg) scale(0.55); + transform-origin: center; + transition: opacity 160ms ease, transform 240ms cubic-bezier(0.16, 1, 0.3, 1); } .client-local-rule-enabled[aria-checked='true'] { @@ -1040,10 +1056,21 @@ p { fill: color-mix(in oklch, var(--client-accent) 12%, transparent); } -.client-local-rule-enabled[aria-checked='true'] path { +.client-local-rule-enabled[aria-checked='true'] .client-rule-check { stroke-dashoffset: 0; } +.client-deletable-row.is-removing .client-local-rule-enabled circle, +.client-deletable-row.is-removing .client-rule-check { + opacity: 0; +} + +.client-deletable-row.is-removing .client-rule-delete-cross { + opacity: 1; + transform: rotate(0) scale(1); + filter: drop-shadow(0 0 3px oklch(0.68 0.15 28 / 0.55)); +} + .client-rule-type { position: relative; min-width: 0; diff --git a/test/web/rule-editor-contract.test.js b/test/web/rule-editor-contract.test.js index 2846b4c..805fd14 100644 --- a/test/web/rule-editor-contract.test.js +++ b/test/web/rule-editor-contract.test.js @@ -21,10 +21,12 @@ test('rule editor add latency stays constant and dirty exits are guarded', () => assert.match(component, /Перезапустить VPN/); assert.match(component, /client-deletable-row/); assert.match(component, /className="client-delete-strike"[\s\S]*onAnimationEnd/); + assert.match(component, /client-rule-delete-cross/); assert.match(styles, /\.client-deletable-row\.is-removing > \.client-delete-strike[\s\S]*client-delete-strike/); - assert.match(styles, /\.client-delete-strike::after[\s\S]*clip-path: polygon\(0 50%[\s\S]*100% 50%/); - assert.match(styles, /\.client-delete-strike \{[\s\S]*z-index: 100[\s\S]*radial-gradient/); + assert.match(styles, /\.client-delete-strike \{[\s\S]*z-index: 100[\s\S]*linear-gradient/); assert.match(styles, /\.client-deletable-row\.is-removing > :not\(\.client-delete-strike\)[\s\S]*z-index: 0/); + assert.match(styles, /\.client-deletable-row\.is-removing > \.client-local-rule-enabled[\s\S]*z-index: 101/); + assert.match(styles, /clip-path: polygon\(0 8%, 100% 50%, 0 92%\)/); assert.match(styles, /@keyframes client-delete-strike[\s\S]*scaleX\(0\)[\s\S]*scaleX\(1\)/); assert.match(styles, /\.client-local-rule:has\(\.client-rule-type\.is-open\)[\s\S]*z-index: 5/); });