cobalt/web/src/components/sidebar/SidebarTab.svelte
wukko 0ae5cad2f5
web: fix PageNavTab & SidebarTab bg flicker on selection
it used to be: normal-> hover -> pressed -> hover -> active

but now it's: normal -> hover -> pressed -> active
2025-02-25 00:37:18 +06:00

172 lines
3.9 KiB
Svelte

<script lang="ts">
import { page } from "$app/stores";
import { t } from "$lib/i18n/translations";
export let name: string;
export let path: string;
export let icon: ConstructorOfATypedSvelteComponent;
export let beta = false;
const firstTabPage = ["save", "remux", "settings"];
let tab: HTMLElement;
$: currentTab = $page.url.pathname.split("/")[1];
$: baseTabPath = path.split("/")[1];
$: isTabActive = currentTab === baseTabPath;
const showTab = (e: HTMLElement) => {
if (e) {
e.scrollIntoView({
inline: firstTabPage.includes(name) ? "end" : "start",
block: "nearest",
behavior: "smooth",
});
}
};
$: if (isTabActive && tab) {
showTab(tab);
}
</script>
<a
id="sidebar-tab-{name}"
class="sidebar-tab"
class:active={isTabActive}
href={path}
bind:this={tab}
on:focus={() => showTab(tab)}
role="tab"
aria-selected={isTabActive}
>
{#if beta}
<div class="beta-sign" aria-label={$t("general.beta")}>β</div>
{/if}
<svelte:component this={icon} />
<span class="tab-title">{$t(`tabs.${name}`)}</span>
</a>
<style>
.sidebar-tab {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
gap: 3px;
padding: var(--sidebar-tab-padding) 3px;
color: var(--sidebar-highlight);
font-size: var(--sidebar-font-size);
opacity: 0.75;
height: fit-content;
border-radius: var(--border-radius);
transition: transform 0.2s;
text-decoration: none;
text-decoration-line: none;
position: relative;
scroll-behavior: smooth;
cursor: pointer;
}
.sidebar-tab :global(svg) {
stroke-width: 1.2px;
height: 22px;
width: 22px;
}
:global([data-iphone="true"] .sidebar-tab svg) {
will-change: transform;
}
.sidebar-tab.active {
color: var(--sidebar-bg);
background: var(--sidebar-highlight);
opacity: 1;
transform: none;
transition: none;
animation: pressButton 0.3s;
cursor: default;
}
.sidebar-tab:not(.active):active {
transform: scale(0.95);
}
:global([data-reduce-motion="true"]) .sidebar-tab:active {
transform: none;
}
.beta-sign {
position: absolute;
transform: translateX(16px) translateY(-6px);
opacity: 0.7;
}
.tab-title {
white-space: nowrap;
}
@keyframes pressButton {
0% {
transform: scale(0.9);
}
50% {
transform: scale(1.015);
}
100% {
transform: scale(1);
}
}
@media (hover: hover) {
.sidebar-tab:hover:not(.active) {
background-color: var(--button-hover-transparent);
}
.sidebar-tab:active:not(.active),
.sidebar-tab:focus:hover:not(.active) {
background-color: var(--button-press-transparent);
}
.sidebar-tab:hover:not(.active),
.sidebar-tab:active:not(.active),
.sidebar-tab:focus:hover:not(.active) {
opacity: 1;
box-shadow: 0 0 0 1.5px var(--sidebar-stroke) inset;
}
}
@media screen and (max-width: 535px) {
.sidebar-tab {
padding: 5px var(--padding);
min-width: calc(var(--sidebar-width) / 2);
}
.sidebar-tab.active {
z-index: 2;
}
.sidebar-tab:active:not(.active) {
transform: scale(0.9);
}
@keyframes pressButton {
0% {
transform: scale(0.8);
}
50% {
transform: scale(1.02);
}
100% {
transform: scale(1);
}
}
}
</style>