2026-02-02 11:59:57 +03:00
|
|
|
<!--
|
|
|
|
|
Component: BreadcrumbHeader
|
|
|
|
|
Fixed header for breadcrumbs navigation for sections in the page
|
|
|
|
|
-->
|
|
|
|
|
<script lang="ts">
|
2026-03-02 22:18:41 +03:00
|
|
|
import type { ResponsiveManager } from '$shared/lib';
|
2026-02-04 10:49:13 +03:00
|
|
|
import {
|
2026-03-02 22:18:41 +03:00
|
|
|
Button,
|
|
|
|
|
Label,
|
|
|
|
|
Logo,
|
|
|
|
|
} from '$shared/ui';
|
|
|
|
|
import { getContext } from 'svelte';
|
|
|
|
|
import { cubicOut } from 'svelte/easing';
|
|
|
|
|
import { slide } from 'svelte/transition';
|
|
|
|
|
import {
|
|
|
|
|
type BreadcrumbItem,
|
|
|
|
|
scrollBreadcrumbsStore,
|
|
|
|
|
} from '../../model';
|
|
|
|
|
|
|
|
|
|
const breadcrumbs = $derived(scrollBreadcrumbsStore.scrolledPastItems);
|
|
|
|
|
const responsive = getContext<ResponsiveManager>('responsive');
|
|
|
|
|
|
|
|
|
|
function handleClick(item: BreadcrumbItem) {
|
|
|
|
|
scrollBreadcrumbsStore.scrollTo(item.index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createButtonText(item: BreadcrumbItem) {
|
|
|
|
|
const index = String(item.index + 1).padStart(2, '0');
|
|
|
|
|
if (responsive.isMobileOrTablet) {
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return `${index} // ${item.title}`;
|
|
|
|
|
}
|
2026-02-02 11:59:57 +03:00
|
|
|
</script>
|
|
|
|
|
|
2026-03-02 22:18:41 +03:00
|
|
|
{#if breadcrumbs.length > 0}
|
2026-02-02 11:59:57 +03:00
|
|
|
<div
|
|
|
|
|
transition:slide={{ duration: 200 }}
|
|
|
|
|
class="
|
2026-03-02 22:18:41 +03:00
|
|
|
fixed top-0 left-0 right-0
|
|
|
|
|
h-14
|
|
|
|
|
md:h-16 px-4 md:px-6 lg:px-8
|
|
|
|
|
flex items-center justify-between
|
|
|
|
|
z-40
|
|
|
|
|
bg-surface/90 dark:bg-dark-bg/90 backdrop-blur-md
|
|
|
|
|
border-b border-black/5 dark:border-white/10
|
2026-02-02 11:59:57 +03:00
|
|
|
"
|
|
|
|
|
>
|
2026-03-02 22:18:41 +03:00
|
|
|
<div class="max-w-8xl px-4 sm:px-6 h-full w-full flex items-center justify-between gap-2 sm:gap-4">
|
|
|
|
|
<Logo />
|
2026-02-02 11:59:57 +03:00
|
|
|
|
2026-03-02 22:18:41 +03:00
|
|
|
<nav class="flex items-center overflow-x-auto scrollbar-hide">
|
|
|
|
|
{#each breadcrumbs as item, _ (item.index)}
|
|
|
|
|
{@const active = scrollBreadcrumbsStore.activeIndex === item.index}
|
|
|
|
|
{@const text = createButtonText(item)}
|
|
|
|
|
<div class="ml-1 md:ml-4" transition:slide={{ duration: 200, axis: 'x', easing: cubicOut }}>
|
|
|
|
|
<Button
|
|
|
|
|
class="uppercase"
|
|
|
|
|
variant="tertiary"
|
|
|
|
|
size="xs"
|
|
|
|
|
{active}
|
|
|
|
|
onclick={() => handleClick(item)}
|
|
|
|
|
>
|
|
|
|
|
<Label class="text-inherit">
|
|
|
|
|
{text}
|
|
|
|
|
</Label>
|
|
|
|
|
</Button>
|
2026-02-02 11:59:57 +03:00
|
|
|
</div>
|
|
|
|
|
{/each}
|
|
|
|
|
</nav>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
/* Hide scrollbar but keep functionality */
|
|
|
|
|
.scrollbar-hide {
|
|
|
|
|
-ms-overflow-style: none;
|
|
|
|
|
scrollbar-width: none;
|
|
|
|
|
}
|
|
|
|
|
.scrollbar-hide::-webkit-scrollbar {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
</style>
|