Refine Harbor mode swap and client delete modal animations
All checks were successful
Build and Deploy Gateway / build-and-push (push) Successful in 13s
Build and Deploy Gateway / deploy (push) Successful in 1s

This commit is contained in:
2026-07-11 15:52:56 +03:00
parent befd41933d
commit aa54be9c9b
2 changed files with 69 additions and 25 deletions

View File

@@ -95,7 +95,8 @@ function HarborBrand({ isGateway, gatewayAvailable, gatewayDirect, busy, onSetGa
<em className="harbor-mode-gateway">Gateway</em> <em className="harbor-mode-gateway">Gateway</em>
</span> </span>
<svg className="harbor-mode-swap" viewBox="0 0 18 18" aria-hidden="true"> <svg className="harbor-mode-swap" viewBox="0 0 18 18" aria-hidden="true">
<path d="M3 6h10m-3-3 3 3-3 3M15 12H5m3 3-3-3 3-3" /> <path className="is-connect" d="M3 6h10m-3-3 3 3-3 3" />
<path className="is-gateway" d="M15 12H5m3 3-3-3 3-3" />
</svg> </svg>
<span id="harbor-mode-tooltip" className="harbor-mode-tooltip" role="tooltip"> <span id="harbor-mode-tooltip" className="harbor-mode-tooltip" role="tooltip">
<strong>{gatewayDirect ? 'Harbor Gateway активен' : 'Harbor Gateway доступен'}</strong> <strong>{gatewayDirect ? 'Harbor Gateway активен' : 'Harbor Gateway доступен'}</strong>

View File

@@ -248,22 +248,32 @@ p {
.harbor-brand-control:hover .harbor-mode-connect, .harbor-brand-control:hover .harbor-mode-connect,
.harbor-brand-control:focus-visible .harbor-mode-connect { .harbor-brand-control:focus-visible .harbor-mode-connect {
transform: translateY(-0.14em); animation: harbor-mode-float-front 1500ms ease-in-out infinite;
} }
.harbor-brand-control:hover .harbor-mode-gateway, .harbor-brand-control:hover .harbor-mode-gateway,
.harbor-brand-control:focus-visible .harbor-mode-gateway { .harbor-brand-control:focus-visible .harbor-mode-gateway {
transform: translate(0.42em, 0.5em) scale(0.96); 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:hover .harbor-mode-connect,
.harbor-brand.is-gateway-active .harbor-brand-control:focus-visible .harbor-mode-connect { .harbor-brand.is-gateway-active .harbor-brand-control:focus-visible .harbor-mode-connect {
transform: translate(0.42em, 0.5em) scale(0.96); 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:hover .harbor-mode-gateway,
.harbor-brand.is-gateway-active .harbor-brand-control:focus-visible .harbor-mode-gateway { .harbor-brand.is-gateway-active .harbor-brand-control:focus-visible .harbor-mode-gateway {
transform: translateY(-0.14em); animation-name: harbor-mode-float-front;
}
@keyframes harbor-mode-float-front {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-0.18em); }
}
@keyframes harbor-mode-float-back {
0%, 100% { transform: translate(0.42em, 0.34em) scale(0.96); }
50% { transform: translate(0.42em, 0.58em) scale(0.96); }
} }
.harbor-brand .harbor-mode-swap { .harbor-brand .harbor-mode-swap {
@@ -272,13 +282,25 @@ p {
left: calc(100% + 4px); left: calc(100% + 4px);
width: 14px; width: 14px;
height: 14px; height: 14px;
color: var(--harbor-connect);
opacity: 0.82; opacity: 0.82;
stroke-width: 1.35; stroke-width: 1.35;
transform: translateY(-50%); transform: translateY(-50%);
transition: color 320ms ease, opacity 320ms ease, transform 420ms cubic-bezier(0.16, 1, 0.3, 1); transition: color 320ms ease, opacity 320ms ease, transform 420ms cubic-bezier(0.16, 1, 0.3, 1);
} }
.harbor-mode-swap path {
transform-box: fill-box;
transform-origin: center;
}
.harbor-mode-swap .is-connect {
stroke: var(--harbor-connect);
}
.harbor-mode-swap .is-gateway {
stroke: var(--harbor-gateway);
}
.harbor-mode-tooltip { .harbor-mode-tooltip {
position: absolute; position: absolute;
bottom: calc(100% + 9px); bottom: calc(100% + 9px);
@@ -318,14 +340,29 @@ p {
transition-delay: 120ms, 120ms, 120ms, 0s; transition-delay: 120ms, 120ms, 120ms, 0s;
} }
.harbor-brand.is-gateway-active .harbor-mode-swap {
color: var(--harbor-gateway);
}
.harbor-brand-control:hover .harbor-mode-swap, .harbor-brand-control:hover .harbor-mode-swap,
.harbor-brand-control:focus-visible .harbor-mode-swap { .harbor-brand-control:focus-visible .harbor-mode-swap {
opacity: 1; opacity: 1;
transform: translate(1px, -50%); }
.harbor-brand-control:hover .harbor-mode-swap .is-connect,
.harbor-brand-control:focus-visible .harbor-mode-swap .is-connect {
animation: harbor-arrow-float-up 1500ms ease-in-out infinite;
}
.harbor-brand-control:hover .harbor-mode-swap .is-gateway,
.harbor-brand-control:focus-visible .harbor-mode-swap .is-gateway {
animation: harbor-arrow-float-down 1500ms ease-in-out infinite;
}
@keyframes harbor-arrow-float-up {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-1.5px); }
}
@keyframes harbor-arrow-float-down {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(1.5px); }
} }
.client-instructions-toggle { .client-instructions-toggle {
@@ -946,52 +983,56 @@ p {
.client-delete-confirmation { .client-delete-confirmation {
position: absolute; position: absolute;
inset: 0; top: 50%;
left: 50%;
z-index: 2; z-index: 2;
width: 100%;
min-height: 250px;
display: grid; display: grid;
align-content: center; align-content: center;
gap: 10px; gap: 12px;
padding: 28px; padding: 34px;
border-radius: 20px; border-radius: 20px;
background: color-mix(in oklch, var(--client-panel) 88%, transparent); background: color-mix(in oklch, var(--client-panel) 88%, transparent);
box-shadow: 0 20px 54px oklch(0.08 0.015 145 / 0.12); box-shadow: 0 20px 54px oklch(0.08 0.015 145 / 0.12);
backdrop-filter: blur(16px); backdrop-filter: blur(16px);
transform: translate(-50%, -50%);
animation: client-delete-reveal 480ms cubic-bezier(0.16, 1, 0.3, 1) both; animation: client-delete-reveal 480ms cubic-bezier(0.16, 1, 0.3, 1) both;
} }
.client-delete-confirmation > span { .client-delete-confirmation > span {
color: oklch(0.68 0.15 28); color: oklch(0.68 0.15 28);
font-size: 9px; font-size: 10px;
font-weight: 700; font-weight: 700;
letter-spacing: 0.08em; letter-spacing: 0.08em;
text-transform: uppercase; text-transform: uppercase;
} }
.client-delete-confirmation h2 { .client-delete-confirmation h2 {
font-size: 18px; font-size: 22px;
letter-spacing: -0.04em; letter-spacing: -0.04em;
} }
.client-delete-confirmation p { .client-delete-confirmation p {
color: var(--client-muted); color: var(--client-muted);
font-size: 10px; font-size: 11px;
line-height: 1.65; line-height: 1.7;
} }
.client-delete-actions { .client-delete-actions {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
gap: 8px; gap: 10px;
margin-top: 8px; margin-top: 10px;
} }
.client-delete-actions button { .client-delete-actions button {
padding: 8px 12px; padding: 10px 14px;
border: 0; border: 0;
border-radius: 9px; border-radius: 9px;
background: color-mix(in oklch, var(--client-control) 74%, transparent); background: color-mix(in oklch, var(--client-control) 74%, transparent);
color: var(--client-text); color: var(--client-text);
font-size: 10px; font-size: 11px;
font-weight: 700; font-weight: 700;
cursor: pointer; cursor: pointer;
transition: color 220ms ease, background 220ms ease, transform 220ms ease; transition: color 220ms ease, background 220ms ease, transform 220ms ease;
@@ -1014,8 +1055,8 @@ p {
} }
@keyframes client-delete-reveal { @keyframes client-delete-reveal {
from { opacity: 0; filter: blur(8px); transform: scale(0.97); } from { opacity: 0; filter: blur(8px); transform: translate(-50%, -48%) scale(0.97); }
to { opacity: 1; filter: blur(0); transform: scale(1); } to { opacity: 1; filter: blur(0); transform: translate(-50%, -50%) scale(1); }
} }
.client-form.is-waiting { .client-form.is-waiting {
@@ -1741,7 +1782,7 @@ p {
} }
.client-form { .client-form {
position: static; position: relative;
width: 100%; width: 100%;
transform: none; transform: none;
} }
@@ -1798,9 +1839,11 @@ p {
} }
.harbor-mode-stack em, .harbor-mode-stack em,
.harbor-mode-swap path,
.harbor-brand .harbor-mode-swap, .harbor-brand .harbor-mode-swap,
.harbor-mode-tooltip { .harbor-mode-tooltip {
transition: none; transition: none;
animation: none;
} }
.client-form-content, .client-form-content,