Refine Harbor brand mode hover animation
This commit is contained in:
@@ -74,12 +74,27 @@ function DurationPart({ name, children }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function HarborBrand({ isGateway, gatewayAvailable, gatewayDirect, busy, onSetGatewayAuto }) {
|
function HarborBrand({ isGateway, gatewayAvailable, gatewayDirect, busy, onSetGatewayAuto }) {
|
||||||
|
const [modeAnimating, setModeAnimating] = useState(false);
|
||||||
|
const stopModeAnimationRef = useRef(false);
|
||||||
const product = isGateway ? 'Gateway' : 'Connect';
|
const product = isGateway ? 'Gateway' : 'Connect';
|
||||||
const switchable = !isGateway && gatewayAvailable;
|
const switchable = !isGateway && gatewayAvailable;
|
||||||
const label = gatewayDirect
|
const label = gatewayDirect
|
||||||
? 'Игнорировать Harbor Gateway и использовать локальный VPN'
|
? 'Игнорировать Harbor Gateway и использовать локальный VPN'
|
||||||
: 'Использовать обнаруженный Harbor Gateway';
|
: 'Использовать обнаруженный Harbor Gateway';
|
||||||
|
|
||||||
|
function startModeAnimation() {
|
||||||
|
stopModeAnimationRef.current = false;
|
||||||
|
setModeAnimating(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishModeAnimation() {
|
||||||
|
if (matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
||||||
|
setModeAnimating(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stopModeAnimationRef.current = true;
|
||||||
|
}
|
||||||
|
|
||||||
const content = <div className="harbor-brand-content">
|
const content = <div className="harbor-brand-content">
|
||||||
<svg viewBox="0 0 32 32" aria-hidden="true">
|
<svg viewBox="0 0 32 32" aria-hidden="true">
|
||||||
<circle cx="16" cy="6" r="3" />
|
<circle cx="16" cy="6" r="3" />
|
||||||
@@ -111,12 +126,22 @@ function HarborBrand({ isGateway, gatewayAvailable, gatewayDirect, busy, onSetGa
|
|||||||
return (
|
return (
|
||||||
<div className={`harbor-brand is-${product.toLowerCase()}${switchable ? ` is-switchable${gatewayDirect ? ' is-gateway-active' : ''}` : ''}`}>
|
<div className={`harbor-brand is-${product.toLowerCase()}${switchable ? ` is-switchable${gatewayDirect ? ' is-gateway-active' : ''}` : ''}`}>
|
||||||
{switchable ? <button
|
{switchable ? <button
|
||||||
className="harbor-brand-control"
|
className={`harbor-brand-control${modeAnimating ? ' is-mode-animating' : ''}`}
|
||||||
type="button"
|
type="button"
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
aria-describedby="harbor-mode-tooltip"
|
aria-describedby="harbor-mode-tooltip"
|
||||||
aria-pressed={gatewayDirect}
|
aria-pressed={gatewayDirect}
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
|
onPointerEnter={startModeAnimation}
|
||||||
|
onPointerLeave={finishModeAnimation}
|
||||||
|
onFocus={startModeAnimation}
|
||||||
|
onBlur={finishModeAnimation}
|
||||||
|
onAnimationIteration={(event) => {
|
||||||
|
if (event.animationName === 'harbor-mode-float-front' && stopModeAnimationRef.current) {
|
||||||
|
stopModeAnimationRef.current = false;
|
||||||
|
setModeAnimating(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
onClick={() => onSetGatewayAuto(!gatewayDirect)}
|
onClick={() => onSetGatewayAuto(!gatewayDirect)}
|
||||||
>
|
>
|
||||||
{content}
|
{content}
|
||||||
|
|||||||
@@ -246,23 +246,19 @@ p {
|
|||||||
transform: none;
|
transform: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.harbor-brand-control:hover .harbor-mode-connect,
|
.harbor-brand-control.is-mode-animating .harbor-mode-connect {
|
||||||
.harbor-brand-control:focus-visible .harbor-mode-connect {
|
|
||||||
animation: harbor-mode-float-front 1500ms ease-in-out infinite;
|
animation: harbor-mode-float-front 1500ms ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.harbor-brand-control:hover .harbor-mode-gateway,
|
.harbor-brand-control.is-mode-animating .harbor-mode-gateway {
|
||||||
.harbor-brand-control:focus-visible .harbor-mode-gateway {
|
|
||||||
animation: harbor-mode-float-back 1500ms ease-in-out infinite;
|
animation: harbor-mode-float-back 1500ms ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.harbor-brand.is-gateway-active .harbor-brand-control:hover .harbor-mode-connect,
|
.harbor-brand.is-gateway-active .harbor-brand-control.is-mode-animating .harbor-mode-connect {
|
||||||
.harbor-brand.is-gateway-active .harbor-brand-control:focus-visible .harbor-mode-connect {
|
|
||||||
animation-name: harbor-mode-float-back;
|
animation-name: harbor-mode-float-back;
|
||||||
}
|
}
|
||||||
|
|
||||||
.harbor-brand.is-gateway-active .harbor-brand-control:hover .harbor-mode-gateway,
|
.harbor-brand.is-gateway-active .harbor-brand-control.is-mode-animating .harbor-mode-gateway {
|
||||||
.harbor-brand.is-gateway-active .harbor-brand-control:focus-visible .harbor-mode-gateway {
|
|
||||||
animation-name: harbor-mode-float-front;
|
animation-name: harbor-mode-float-front;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,13 +353,11 @@ p {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.harbor-brand-control:hover .harbor-mode-swap .is-connect path,
|
.harbor-brand-control.is-mode-animating .harbor-mode-swap .is-connect path {
|
||||||
.harbor-brand-control:focus-visible .harbor-mode-swap .is-connect path {
|
|
||||||
animation: harbor-arrow-float-right 1500ms ease-in-out infinite;
|
animation: harbor-arrow-float-right 1500ms ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.harbor-brand-control:hover .harbor-mode-swap .is-gateway path,
|
.harbor-brand-control.is-mode-animating .harbor-mode-swap .is-gateway path {
|
||||||
.harbor-brand-control:focus-visible .harbor-mode-swap .is-gateway path {
|
|
||||||
animation: harbor-arrow-float-left 1500ms ease-in-out infinite;
|
animation: harbor-arrow-float-left 1500ms ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user