1
0
mirror of https://github.com/garraflavatra/rolens.git synced 2025-01-18 13:07:58 +00:00

Add sliding active tab indicator

This commit is contained in:
Romein van Buren 2023-12-22 14:02:58 +01:00
parent d1b1c7daa5
commit 9eac9ae935
Signed by: romein
GPG Key ID: 0EFF8478ADDF6C49

View File

@ -1,5 +1,7 @@
<script> <script>
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher, onMount } from 'svelte';
import { tweened } from 'svelte/motion';
import { cubicInOut } from 'svelte/easing';
import Icon from './icon.svelte'; import Icon from './icon.svelte';
export let tabs = []; export let tabs = [];
@ -8,19 +10,54 @@
export let compact = true; export let compact = true;
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
const activeIndicatorLeft = tweened(0, { easing: cubicInOut, duration: 400 });
const activeIndicatorRight = tweened(0, { easing: cubicInOut, duration: 400 });
const liElements = {};
let navEl; let navEl;
let activeLiEl;
function select(tabKey) { function select(tabKey, activeLi) {
selectedKey = tabKey; selectedKey = tabKey;
activeLiEl = activeLi;
dispatch('select', tabKey); dispatch('select', tabKey);
} }
function moveActiveIndicator(target) {
if (!compact) {
return;
}
const navRect = navEl.getBoundingClientRect();
if (!target) {
const activeLiRect = activeLiEl?.getBoundingClientRect() || navRect;
$activeIndicatorLeft = activeLiRect.x - navRect.x;
$activeIndicatorRight = navRect.right - activeLiRect.right;
}
const itemRect = target.getBoundingClientRect();
$activeIndicatorLeft = itemRect.x - navRect.x;
$activeIndicatorRight = navRect.right - itemRect.right;
}
onMount(() => {
if (selectedKey) {
moveActiveIndicator(liElements[selectedKey]);
}
});
</script> </script>
<nav class="tabs" class:compact bind:this={navEl}> <nav class="tabs" class:compact bind:this={navEl}>
<ul> <ul>
{#each tabs as tab (tab.key)} {#each tabs as tab (tab.key)}
<li class="tab" class:active={tab.key === selectedKey} class:closable={tab.closable}> <li
<button class="tab" on:click={() => select(tab.key)}> class="tab"
class:active={tab.key === selectedKey}
class:closable={tab.closable}
bind:this={liElements[tab.key]}
on:mouseenter={event => moveActiveIndicator(event.target)}
on:mouseleave={() => moveActiveIndicator()}
>
<button class="tab" on:click={event => select(tab.key, event.target.parentElement)}>
{#if tab.icon} <Icon name={tab.icon} /> {/if} {#if tab.icon} <Icon name={tab.icon} /> {/if}
<span class="label">{tab.title}</span> <span class="label">{tab.title}</span>
</button> </button>
@ -41,9 +78,21 @@
</li> </li>
{/if} {/if}
</ul> </ul>
{#if compact}
<span
class="activeindicator"
style:left="{$activeIndicatorLeft}px"
style:right="{$activeIndicatorRight}px"
/>
{/if}
</nav> </nav>
<style> <style>
nav {
position: relative;
}
ul { ul {
overflow-x: auto; overflow-x: auto;
display: flex; display: flex;
@ -110,18 +159,17 @@
nav.tabs.compact li { nav.tabs.compact li {
border-bottom: 2px solid transparent; border-bottom: 2px solid transparent;
} }
nav.tabs.compact li.tab:hover,
nav.tabs.compact li.tab.active {
color: var(--primary);
border-color: var(--primary);
}
nav.tabs.compact button.tab { nav.tabs.compact button.tab {
border: none; border: none;
color: inherit; color: inherit;
background-color: transparent; background-color: transparent;
border-width: 0;
} }
nav.tabs.compact li.active button.tab {
border-bottom-width: 2px; .activeindicator {
display: block;
position: absolute;
bottom: -1px;
height: 2px;
background-color: var(--primary);
} }
</style> </style>