feat(HEL-251): 按确认稿实现登录页动态小K线人物

在桌面登录门户品牌空白带加入红绿小K线角色,支持焦点、密码遮挡、登录反馈和减少动态效果,且不移动原有文案与行情图。

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
总工
2026-08-29 21:46:05 +08:00
co-authored by Cursor multica-agent
parent 865d8b0516
commit 4a63ccd10f
6 changed files with 839 additions and 7 deletions
+383 -3
View File
@@ -1827,16 +1827,351 @@ body.login-portal {
opacity: 0.72;
}
.login-brand-copy {
.login-mascots {
display: flex;
flex: 1 1 auto;
align-items: center;
min-height: 0;
pointer-events: none;
}
.login-mascots-stage {
display: flex;
align-items: flex-end;
padding-left: calc(var(--login-mascot-height) * 82 / 210);
gap: calc(var(--login-mascot-height) * 10 / 210);
}
.login-mascot {
position: relative;
flex: 0 0 auto;
overflow: visible;
--pupil-x: 0px;
--pupil-y: 0px;
--lean: 0deg;
}
.login-mascot.is-red {
width: calc(var(--login-mascot-height) * 96 / 210);
height: var(--login-mascot-height);
}
.login-mascot.is-green {
width: calc(var(--login-mascot-height) * 84 / 210);
height: calc(var(--login-mascot-height) * 175 / 210);
perspective: 420px;
}
.login-mascot-breathe {
width: 100%;
height: 100%;
transform-origin: 50% 100%;
}
.login-mascots[data-mood="idle"] .login-mascot-breathe {
animation: login-mascot-breathe 3.6s ease-in-out infinite;
}
.login-mascot-lean {
width: 100%;
height: 100%;
transform: rotate(var(--lean));
transform-origin: 50% 88%;
}
.login-mascot.is-red .login-mascot-figure {
display: block;
width: 100%;
height: 100%;
}
.login-mascot.is-green .login-mascot-figure {
position: relative;
width: 100%;
height: 100%;
transform-style: preserve-3d;
transition: transform 280ms ease-in-out;
}
.login-mascot-front {
display: block;
width: 100%;
height: 100%;
backface-visibility: hidden;
}
.login-mascot-back {
position: absolute;
inset: 0;
display: block;
width: 100%;
height: 100%;
backface-visibility: hidden;
transform: rotateY(180deg);
}
.login-mascots[data-mood="password"] .login-mascot.is-green .login-mascot-figure {
transform: rotateY(180deg);
}
.login-mascot-body {
fill: var(--login-mascot-red);
}
.login-mascot.is-green .login-mascot-body {
fill: var(--login-mascot-green);
}
.login-mascot-wick {
stroke: var(--login-mascot-red);
stroke-width: 4;
stroke-linecap: round;
}
.login-mascot.is-green .login-mascot-wick {
stroke: var(--login-mascot-green);
stroke-width: 3.5;
}
.login-mascot-eye {
fill: var(--login-mascot-eye);
}
.login-mascot-pupil {
fill: var(--login-mascot-pupil);
transform: translate(var(--pupil-x), var(--pupil-y));
transform-box: fill-box;
transform-origin: center;
}
.login-mascot-lid {
fill: var(--login-mascot-red);
transform: scaleY(0);
transform-box: fill-box;
transform-origin: center;
}
.login-mascot.is-green .login-mascot-lid {
fill: var(--login-mascot-green);
}
.login-mascots.is-blinking .login-mascot-lid {
animation: login-mascot-blink 140ms ease-out;
}
.login-mascot-happy {
fill: none;
stroke: var(--login-mascot-pupil);
stroke-width: 2.4;
stroke-linecap: round;
opacity: 0;
}
.login-mascot-sad {
fill: var(--login-mascot-pupil);
opacity: 0;
}
.login-mascot-arm {
fill: var(--login-mascot-red);
transform-box: fill-box;
transform-origin: center;
transition: transform 250ms cubic-bezier(0.2, 0.9, 0.25, 1.2);
}
.login-mascot.is-green .login-mascot-arm {
fill: var(--login-mascot-green);
}
.login-mascot-hand {
fill: var(--login-mascot-red-shade);
opacity: 0;
transform-box: fill-box;
transform-origin: center;
transition: transform 250ms cubic-bezier(0.2, 0.9, 0.25, 1.2), opacity 180ms ease-out;
}
.login-mascots[data-mood="password"] .login-mascot.is-red .login-mascot-hand {
opacity: 1;
}
.login-mascots[data-mood="password"] .login-mascot.is-red .login-mascot-hand.is-left {
transform: translate(20px, -34px) scale(1.2);
}
.login-mascots[data-mood="password"] .login-mascot.is-red .login-mascot-hand.is-right {
transform: translate(-20px, -34px) scale(1.2);
}
.login-mascots[data-mood="password"] .login-mascot.is-red .login-mascot-arm.is-left {
transform: translate(10px, -18px) rotate(-18deg);
}
.login-mascots[data-mood="password"] .login-mascot.is-red .login-mascot-arm.is-right {
transform: translate(-10px, -18px) rotate(18deg);
}
.login-mascots[data-mood="password"] .login-mascot.is-red .login-mascot-pupil,
.login-mascots[data-mood="password"] .login-mascot.is-red .login-mascot-eye {
opacity: 0;
}
.login-mascot-slit {
fill: var(--login-mascot-green-shade);
}
.login-mascot-shadow {
fill: rgba(6, 10, 24, 0.28);
}
.login-mascots[data-mood="success"] .login-mascot-pupil,
.login-mascots[data-mood="success"] .login-mascot-lid,
.login-mascots[data-mood="fail"] .login-mascot-pupil {
opacity: 0;
}
.login-mascots[data-mood="success"] .login-mascot-happy,
.login-mascots[data-mood="fail"] .login-mascot-sad {
opacity: 1;
}
.login-mascots[data-mood="success"] .login-mascot.is-red .login-mascot-arm.is-left {
transform: translate(-2px, -36px) rotate(-48deg);
}
.login-mascots[data-mood="success"] .login-mascot.is-red .login-mascot-arm.is-right {
transform: translate(2px, -36px) rotate(48deg);
}
.login-mascots[data-mood="success"] .login-mascot.is-red {
animation: login-mascot-hop-red 450ms ease-in-out;
}
.login-mascots[data-mood="success"] .login-mascot.is-green {
animation: login-mascot-hop-green 450ms ease-in-out 80ms;
}
.login-mascots[data-mood="fail"] .login-mascot-arm {
transform: translateY(6px);
}
@media (prefers-reduced-motion: reduce) {
.login-mascots[data-mood="idle"] .login-mascot-breathe,
.login-mascots.is-blinking .login-mascot-lid,
.login-mascots[data-mood="success"] .login-mascot.is-red,
.login-mascots[data-mood="success"] .login-mascot.is-green {
animation: none;
}
.login-mascot.is-green .login-mascot-figure,
.login-mascot-hand,
.login-mascot-arm {
transition: none;
}
}
.login-password-wrap {
position: relative;
display: block;
}
.login-portal .login-password-wrap input {
padding-right: 48px;
}
.login-password-toggle {
position: absolute;
top: 50%;
right: 8px;
z-index: 1;
min-height: 24px;
padding: 0;
border: 0;
background: transparent;
color: var(--text-secondary);
font-size: var(--font-size-caption);
transform: translateY(-50%);
cursor: pointer;
}
.login-brand-copy {
display: flex;
flex: 0 0 auto;
flex-direction: column;
justify-content: flex-end;
padding: 24px 0 20px;
padding: 0 0 20px;
}
.login-brand-kicker {
@@ -2119,6 +2454,50 @@ body.login-portal {
}
}
@keyframes login-mascot-breathe {
0%,
100% {
transform: scaleY(1);
}
50% {
transform: scaleY(1.015);
}
}
@keyframes login-mascot-blink {
0%,
100% {
transform: scaleY(0);
}
50% {
transform: scaleY(1);
}
}
@keyframes login-mascot-hop-red {
0%,
100% {
transform: translateY(0);
}
42% {
transform: translateY(-13px);
}
}
@keyframes login-mascot-hop-green {
0%,
100% {
transform: translateY(0);
}
42% {
transform: translateY(-11px);
}
}
.login-error {
margin: 0;
@@ -2466,7 +2845,8 @@ body.login-portal {
.login-brand-copy,
.login-brand-market,
.login-brand-disclaimer {
.login-brand-disclaimer,
.login-mascots {
display: none;
}
+7
View File
@@ -165,6 +165,13 @@
--login-candle-up: #e07078;
--login-candle-down: #3db88a;
--login-trend-line: rgba(244, 247, 255, 0.88);
--login-mascot-red: #e8605a;
--login-mascot-red-shade: #c74a45;
--login-mascot-green: #46be93;
--login-mascot-green-shade: #37997a;
--login-mascot-eye: #f7f9fc;
--login-mascot-pupil: #1a2440;
--login-mascot-height: clamp(150px, 15vw, 260px);
--font-size-aux: 11.5px;
--font-size-caption: 12.5px;