refactor(Breadcrumb): simplify entity structure and add tests
This commit is contained in:
@@ -3,65 +3,72 @@
|
||||
Fixed header for breadcrumbs navigation for sections in the page
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { smoothScroll } from '$shared/lib';
|
||||
import { cn } from '$shared/shadcn/utils/shadcn-utils';
|
||||
import type { ResponsiveManager } from '$shared/lib';
|
||||
import {
|
||||
fly,
|
||||
slide,
|
||||
} from 'svelte/transition';
|
||||
import { scrollBreadcrumbsStore } from '../../model';
|
||||
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}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if scrollBreadcrumbsStore.items.length > 0}
|
||||
{#if breadcrumbs.length > 0}
|
||||
<div
|
||||
transition:slide={{ duration: 200 }}
|
||||
class="
|
||||
fixed top-0 left-0 right-0 z-100
|
||||
backdrop-blur-lg bg-background-20
|
||||
border-b border-border-muted
|
||||
shadow-[0_1px_3px_rgba(0,0,0,0.04)]
|
||||
h-10 sm:h-12
|
||||
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
|
||||
"
|
||||
>
|
||||
<div class="max-w-8xl mx-auto px-4 sm:px-6 h-full flex items-center gap-2 sm:gap-4">
|
||||
<h1 class={cn('barlow font-extralight text-sm sm:text-base')}>
|
||||
GLYPHDIFF
|
||||
</h1>
|
||||
<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 />
|
||||
|
||||
<div class="h-3.5 sm:h-4 w-px bg-border-subtle hidden sm:block"></div>
|
||||
|
||||
<nav class="flex items-center gap-2 sm:gap-3 overflow-x-auto scrollbar-hide flex-1">
|
||||
{#each scrollBreadcrumbsStore.items as item, idx (item.index)}
|
||||
<div
|
||||
in:fly={{ duration: 300, y: -10, x: 100, opacity: 0 }}
|
||||
out:fly={{ duration: 300, y: 10, x: 100, opacity: 0 }}
|
||||
class="flex items-center gap-2 sm:gap-3 whitespace-nowrap shrink-0"
|
||||
>
|
||||
<span class="font-mono text-[8px] sm:text-[9px] text-text-muted tracking-wider">
|
||||
{String(item.index).padStart(2, '0')}
|
||||
</span>
|
||||
<a href={`#${item.id}`} use:smoothScroll>
|
||||
{@render item.title({
|
||||
className: 'text-[9px] sm:text-[10px] font-bold uppercase tracking-tight leading-[0.95] text-foreground',
|
||||
})}</a>
|
||||
|
||||
{#if idx < scrollBreadcrumbsStore.items.length - 1}
|
||||
<div class="flex items-center gap-0.5 opacity-40">
|
||||
<div class="w-1 h-px bg-text-muted"></div>
|
||||
<div class="w-1 h-px bg-text-muted"></div>
|
||||
<div class="w-1 h-px bg-text-muted"></div>
|
||||
</div>
|
||||
{/if}
|
||||
<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>
|
||||
</div>
|
||||
{/each}
|
||||
</nav>
|
||||
|
||||
<div class="flex items-center gap-1.5 sm:gap-2 opacity-50 ml-auto">
|
||||
<div class="w-px h-2 sm:h-2.5 bg-border-subtle hidden sm:block"></div>
|
||||
<span class="font-mono text-[7px] sm:text-[8px] text-text-muted tracking-wider">
|
||||
[{scrollBreadcrumbsStore.items.length}]
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user