diff --git a/src/shared/ui/Section/Section.svelte b/src/shared/ui/Section/Section.svelte index 9d0c7fd..2648797 100644 --- a/src/shared/ui/Section/Section.svelte +++ b/src/shared/ui/Section/Section.svelte @@ -11,7 +11,9 @@ import { type FlyParams, fly, } from 'svelte/transition'; -import { Footnote } from '..'; + +import SectionHeader from './SectionHeader/SectionHeader.svelte'; +import SectionTitle from './SectionTitle/SectionTitle.svelte'; interface Props extends Omit, 'title'> { /** @@ -23,17 +25,15 @@ interface Props extends Omit, 'title'> { */ class?: string; /** - * Snippet for a title itself + * Title of the section */ - title?: Snippet<[{ className?: string }]>; - /** - * Snippet for a title icon - */ - icon?: Snippet<[{ className?: string }]>; + title: string; /** * Snippet for a title description */ description?: Snippet<[{ className?: string }]>; + headerTitle?: string; + headerSubtitle?: string; /** * Index of the section */ @@ -57,32 +57,20 @@ interface Props extends Omit, 'title'> { * Snippet for the section content */ content?: Snippet<[{ className?: string }]>; - /** - * When true, the title stays fixed in view while - * scrolling through the section content. - */ - stickyTitle?: boolean; - /** - * Top offset for sticky title (e.g. header height). - * @default '0px' - */ - stickyOffset?: string; } const { class: className, title, - icon, + headerTitle, + headerSubtitle, description, index = 0, onTitleStatusChange, id, content, - stickyTitle = false, - stickyOffset = '0px', }: Props = $props(); -let titleContainer = $state(); const flyParams: FlyParams = { y: 0, x: -50, @@ -90,90 +78,19 @@ const flyParams: FlyParams = { easing: cubicOut, opacity: 0.2, }; - -// Track if the user has actually scrolled away from view -let isScrolledPast = $state(false); - -$effect(() => { - if (!titleContainer) { - return; - } - let cleanup: ((index: number) => void) | undefined; - const observer = new IntersectionObserver( - entries => { - const entry = entries[0]; - const isPast = !entry.isIntersecting && entry.boundingClientRect.top < 0; - - if (isPast !== isScrolledPast) { - isScrolledPast = isPast; - cleanup = onTitleStatusChange?.(index, isPast, title, id); - } - }, - { - // Set threshold to 0 to trigger exactly when the last pixel leaves - threshold: 0, - }, - ); - - observer.observe(titleContainer); - return () => { - observer.disconnect(); - cleanup?.(index); - }; -});
-
-
- {#if icon} - {@render icon({ - className: 'size-3 sm:size-4 stroke-foreground stroke-1 opacity-60', -})} -
- {/if} - - {#if description} - - {#snippet render({ class: className })} - {@render description({ className })} - {/snippet} - - {:else if typeof index === 'number'} - - Component_{String(index).padStart(3, '0')} - - {/if} -
- - {#if title} - {@render title({ - className: - 'text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-semibold tracking-tighter text-foreground leading-[0.9]', -})} +
+ {#if headerTitle} + {/if} +
- - {@render content?.({ - className: stickyTitle - ? 'row-start-2 col-start-2' - : 'row-start-2 col-start-2', -})} + {@render content?.({})}