feature/comparison-slider #19
2
src/entities/Breadcrumb/index.ts
Normal file
2
src/entities/Breadcrumb/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { scrollBreadcrumbsStore } from './model';
|
||||
export { BreadcrumbHeader } from './ui';
|
||||
1
src/entities/Breadcrumb/model/index.ts
Normal file
1
src/entities/Breadcrumb/model/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './store/scrollBreadcrumbsStore.svelte';
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
export interface BreadcrumbItem {
|
||||
index: number;
|
||||
title: Snippet<[{ className?: string }]>;
|
||||
}
|
||||
|
||||
class ScrollBreadcrumbsStore {
|
||||
#items = $state<BreadcrumbItem[]>([]);
|
||||
|
||||
get items() {
|
||||
// Keep them sorted by index for Swiss orderliness
|
||||
return this.#items.sort((a, b) => a.index - b.index);
|
||||
}
|
||||
add(item: BreadcrumbItem) {
|
||||
if (!this.#items.find(i => i.index === item.index)) {
|
||||
this.#items.push(item);
|
||||
}
|
||||
}
|
||||
remove(index: number) {
|
||||
this.#items = this.#items.filter(i => i.index !== index);
|
||||
}
|
||||
}
|
||||
|
||||
export function createScrollBreadcrumbsStore() {
|
||||
return new ScrollBreadcrumbsStore();
|
||||
}
|
||||
|
||||
export const scrollBreadcrumbsStore = createScrollBreadcrumbsStore();
|
||||
@@ -0,0 +1,78 @@
|
||||
<!--
|
||||
Component: BreadcrumbHeader
|
||||
Fixed header for breadcrumbs navigation for sections in the page
|
||||
-->
|
||||
<script lang="ts">
|
||||
import Icon from '@lucide/svelte/icons/align-vertical-justify-center';
|
||||
import { flip } from 'svelte/animate';
|
||||
import { slide } from 'svelte/transition';
|
||||
import { scrollBreadcrumbsStore } from '../../model';
|
||||
</script>
|
||||
|
||||
{#if scrollBreadcrumbsStore.items.length > 0}
|
||||
<div
|
||||
transition:slide={{ duration: 200 }}
|
||||
class="
|
||||
fixed top-0 left-0 right-0 z-100
|
||||
backdrop-blur-lg bg-white/20
|
||||
border-b border-gray-300/50
|
||||
shadow-[0_1px_3px_rgba(0,0,0,0.04)]
|
||||
h-12
|
||||
"
|
||||
>
|
||||
<div class="max-w-8xl mx-auto px-6 h-full flex items-center gap-4">
|
||||
<div class="flex items-center gap-2.5 opacity-70">
|
||||
<Icon class="size-4 stroke-gray-900 stroke-1" />
|
||||
<div class="w-px h-2.5 bg-gray-400/50"></div>
|
||||
<span class="font-mono text-[9px] uppercase tracking-[0.25em] text-gray-500 font-medium">
|
||||
nav_trace
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="h-4 w-px bg-gray-300/60"></div>
|
||||
|
||||
<nav class="flex items-center gap-3 overflow-x-auto scrollbar-hide flex-1">
|
||||
{#each scrollBreadcrumbsStore.items as item, idx (item.index)}
|
||||
<div
|
||||
animate:flip={{ duration: 200 }}
|
||||
class="flex items-center gap-3 whitespace-nowrap shrink-0"
|
||||
>
|
||||
<span class="font-mono text-[9px] text-gray-400 tracking-wider">
|
||||
{String(item.index).padStart(2, '0')}
|
||||
</span>
|
||||
|
||||
{@render item.title({
|
||||
className: 'font-mono text-[10px] font-bold uppercase tracking-tight leading-[0.95] text-gray-900',
|
||||
})}
|
||||
|
||||
{#if idx < scrollBreadcrumbsStore.items.length - 1}
|
||||
<div class="flex items-center gap-0.5 opacity-40">
|
||||
<div class="w-1 h-px bg-gray-400"></div>
|
||||
<div class="w-1 h-px bg-gray-400"></div>
|
||||
<div class="w-1 h-px bg-gray-400"></div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</nav>
|
||||
|
||||
<div class="flex items-center gap-2 opacity-50 ml-auto">
|
||||
<div class="w-px h-2.5 bg-gray-300/60"></div>
|
||||
<span class="font-mono text-[8px] text-gray-400 tracking-wider">
|
||||
[{scrollBreadcrumbsStore.items.length}]
|
||||
</span>
|
||||
</div>
|
||||
</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>
|
||||
3
src/entities/Breadcrumb/ui/index.ts
Normal file
3
src/entities/Breadcrumb/ui/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import BreadcrumbHeader from './BreadcrumbHeader/BreadcrumbHeader.svelte';
|
||||
|
||||
export { BreadcrumbHeader };
|
||||
Reference in New Issue
Block a user