feat(ui): animate sidebar icons on hover

This commit is contained in:
2026-09-11 09:00:44 +03:00
parent d7e8963d1c
commit ebba6ab25d
2 changed files with 123 additions and 16 deletions
+77
View File
@@ -13,6 +13,83 @@
display: none;
}
.navIcon {
display: inline-flex;
flex-shrink: 0;
}
@media (prefers-reduced-motion: no-preference) {
.drawStroke {
stroke-dasharray: 1;
}
.topSlider {
--slider-offset: -3px;
}
.bottomSlider {
--slider-offset: 3px;
}
.navLink:focus-visible {
.portfolioIcon {
animation: portfolio-sway 650ms ease-in-out;
}
.drawStroke {
animation: stroke-draw 650ms ease-in-out;
}
:is(.topSlider, .bottomSlider) {
animation: slider-slide 650ms ease-in-out;
}
}
@media (hover: hover) {
.navLink:hover {
.portfolioIcon {
animation: portfolio-sway 650ms ease-in-out;
}
.drawStroke {
animation: stroke-draw 650ms ease-in-out;
}
:is(.topSlider, .bottomSlider) {
animation: slider-slide 650ms ease-in-out;
}
}
}
}
@keyframes portfolio-sway {
0%,
100% {
transform: rotate(0);
}
30% {
transform: translateY(-1px) rotate(-10deg);
}
65% {
transform: rotate(7deg);
}
}
@keyframes stroke-draw {
0% {
stroke-dashoffset: 1;
}
100% {
stroke-dashoffset: 0;
}
}
@keyframes slider-slide {
0%,
100% {
transform: translateX(0);
}
50% {
transform: translateX(var(--slider-offset));
}
}
@media (max-width: 47.99375em) {
.bottomNav {
background: var(--mantine-color-white);
+46 -16
View File
@@ -16,6 +16,7 @@ const AppShell: FC<AppShellProps> = (props) => {
{
to: "/accounts",
label: t("navigation.accounts"),
iconClassName: classes.portfolioIcon,
icon: (
<path d="M8 6V4h8v2M3 10h18M9 10v3h6v-3M5 6h14a2 2 0 0 1 2 2v11H3V8a2 2 0 0 1 2-2Z" />
),
@@ -23,18 +24,42 @@ const AppShell: FC<AppShellProps> = (props) => {
{
to: "/stocks",
label: t("navigation.stocks"),
icon: <path d="M3 3v18h18M7 14l5-5 4 3 5-7M16 5h5v5" />,
icon: (
<>
<path d="M3 3v18h18" />
<path
className={classes.drawStroke}
pathLength={1}
d="M7 14l5-5 4 3 5-7M16 5h5v5"
/>
</>
),
},
{
to: "/bonds",
label: t("navigation.bonds"),
icon: <path d="M6 3h12v18l-3-2-3 2-3-2-3 2V3ZM9 7h6M9 11h6M9 15h3" />,
icon: (
<>
<path d="M6 3h12v18l-3-2-3 2-3-2-3 2V3Z" />
<path
className={classes.drawStroke}
pathLength={1}
d="M9 7h6M9 11h6M9 15h3"
/>
</>
),
},
{
to: "/settings",
label: t("navigation.settings"),
icon: (
<path d="M4 7h9m4 0h3M4 17h3m4 0h9M13 4v6h4V4h-4ZM7 14v6h4v-6H7Z" />
<>
<path className={classes.topSlider} d="M4 7h9m4 0h3M13 4v6h4V4h-4Z" />
<path
className={classes.bottomSlider}
d="M4 17h3m4 0h9M7 14v6h4v-6H7Z"
/>
</>
),
},
];
@@ -52,24 +77,29 @@ const AppShell: FC<AppShellProps> = (props) => {
{items.map((item) => (
<NavLink
component={RouterNavLink}
className={classes.navLink}
key={item.to}
to={item.to}
label={item.label}
leftSection={
<svg
width={20}
height={20}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
focusable="false"
<span
className={`${classes.navIcon} ${item.iconClassName ?? ""}`}
>
{item.icon}
</svg>
<svg
width={20}
height={20}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
focusable="false"
>
{item.icon}
</svg>
</span>
}
active={pathname.startsWith(item.to)}
/>