-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Sebastian Flick
committed
Nov 4, 2024
1 parent
1610bb7
commit dbe9ce7
Showing
5 changed files
with
197 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/** @type {import('./$types').PageLoad} */ | ||
export async function load({ params }) { | ||
return { | ||
thirties: params.thirties | ||
}; | ||
} | ||
|
||
export const prerender = false; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,31 @@ | ||
<script> | ||
import { base } from '$app/paths'; | ||
import FassungenContent from './FassungenContent.svelte'; | ||
/** @type {{data: import('./$types').PageData}} */ | ||
let { data } = $props(); | ||
let localPages = $state([]); | ||
$effect(() => { | ||
localPages = fetch(`${base}/fassungen/data/${data.thirties}`).then((r) => r.json()); | ||
}); | ||
</script> | ||
|
||
<h1>Fassung eines bestimmten Dreissigers</h1> | ||
<section class="w-full"> | ||
<h1 class="h1 my-4">Fassungsansicht</h1> | ||
<div class="grid gap-6 md:grid-cols-2 md:my-8"> | ||
<p>Einstellungen und Links zu den Textzeugen.</p> | ||
</div> | ||
{#await localPages} | ||
<p>loading...</p> | ||
{:then pagearray} | ||
<div | ||
class="grid grid-cols-[repeat(auto-fit,minmax(400px,1fr))] gap-4 bg-surface-active-token my-4 py-4 px-8 rounded-xl" | ||
> | ||
{#each pagearray as pages} | ||
<FassungenContent {pages} /> | ||
{/each} | ||
</div> | ||
{/await} | ||
</section> |
159 changes: 159 additions & 0 deletions
159
src/routes/fassungen/[thirties]/FassungenContent.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
<script> | ||
import { onMount } from 'svelte'; | ||
/** @type {{pages: any}} */ | ||
let { pages, localPageChange, localIiifChange, localVerseChange, targetverse } = $props(); | ||
let localTarget; | ||
/** | ||
* @type {number | null} | ||
*/ | ||
let timer = $state(null); | ||
let scrollContainer = $state(); | ||
/** | ||
* @type {IntersectionObserver} | ||
*/ | ||
let observer; | ||
onMount(() => { | ||
observer = new IntersectionObserver( | ||
(entries) => { | ||
entries.forEach((entry) => { | ||
if (entry.isIntersecting) { | ||
localPageChange(entry.target.dataset); | ||
} | ||
}); | ||
}, | ||
{ | ||
root: scrollContainer, | ||
rootMargin: '0px', | ||
threshold: [0, 1] | ||
} | ||
); | ||
}); | ||
let programmaticScroll = $state(false); | ||
let oldHeight = $state(0); | ||
const onScrollEnd = (/** @type { Event & { target: HTMLElement}} } */ e) => { | ||
if (programmaticScroll || scrollContainer.scrollHeight > oldHeight) { | ||
programmaticScroll = false; | ||
oldHeight = scrollContainer.scrollHeight; | ||
} else { | ||
clearTimeout(timer); | ||
timer = setTimeout(() => { | ||
const positive = (/** @type {string} */ verse) => { | ||
localVerseChange(verse); | ||
}; | ||
const /** @type { NodeListOf<HTMLElement> } */ verses = | ||
e.target?.querySelectorAll('.verse'); | ||
let found = false; | ||
for (let i = 0; i < verses.length; i++) { | ||
const verse = verses[i]; | ||
if ( | ||
verse.getBoundingClientRect().top === e.target.getBoundingClientRect().top && | ||
verse.dataset.verse | ||
) { | ||
positive(verse.dataset.verse); | ||
found = true; | ||
break; | ||
} | ||
} | ||
if (!found) { | ||
for (let i = 0; i < verses.length; i++) { | ||
const verse = verses[i]; | ||
if ( | ||
verse.getBoundingClientRect().top >= e.target.getBoundingClientRect().top && | ||
verse.dataset.verse | ||
) { | ||
positive(verse.dataset.verse); | ||
break; | ||
} | ||
} | ||
} | ||
timer = null; | ||
}, 200); | ||
} | ||
}; | ||
const scroll = async (/** @type {String} */ target) => { | ||
programmaticScroll = true; | ||
//wait for promises in pages to resolve before scrolling | ||
await Promise.all( | ||
pages.map((/** @type {{ tpData: any; }} */ page) => { | ||
return page.tpData; | ||
}) | ||
); | ||
const verse = scrollContainer?.querySelector(`[data-verse="${target}"]`); | ||
if (!verse && scrollContainer) { | ||
//check whether the verse should be there | ||
// goto( | ||
// `${base}/textzeugen/${$page.params.sigla}/${target.replace('.', '/')}?${$page.url.searchParams.toString()}` | ||
// ); | ||
console.log('Verse not found.', target, scrollContainer); | ||
return; | ||
} | ||
if (!scrollContainer) { | ||
return; | ||
} | ||
// verse.scrollIntoView({ behavior: 'instant', block: 'start' }); | ||
scrollContainer?.scrollTo({ | ||
top: | ||
scrollContainer?.scrollTop + | ||
Number(verse.parentElement?.getBoundingClientRect().top) - | ||
scrollContainer?.getBoundingClientRect().top, | ||
behavior: 'instant' | ||
}); | ||
verse.parentElement?.classList.add('animate-pulse', 'once'); | ||
// check whether the verse is on the last page in the scrollcontainer | ||
if (scrollContainer.scrollHeight - scrollContainer.clientHeight === scrollContainer.scrollTop) { | ||
const dataset = verse.parentElement?.dataset; | ||
if (dataset) { | ||
localPageChange(dataset); | ||
} | ||
} | ||
}; | ||
$effect(() => { | ||
//this effect rerons more often than it should, sometimes the value of targetverse didn't even change this is why we need to keep track of the target ourselves | ||
if (localTarget !== targetverse) { | ||
localTarget = targetverse; | ||
scroll(targetverse); | ||
} | ||
}); | ||
const addToObserver = (/** @type {HTMLDivElement} */ node) => { | ||
$effect(() => { | ||
observer.observe(node); | ||
return () => { | ||
observer.unobserve(node); | ||
}; | ||
}); | ||
}; | ||
</script> | ||
<div class="max-h-[70vh] overflow-y-auto" bind:this={scrollContainer}> | ||
{#if pages} | ||
<div class="thirty" use:addToObserver> | ||
{@html pages} | ||
</div> | ||
<hr class="!border-t-4 !border-primary-500" /> | ||
{/if} | ||
</div> | ||
<style> | ||
.thirty { | ||
:global(.once) { | ||
-webkit-animation-iteration-count: 4; | ||
animation-iteration-count: 4; | ||
} | ||
:global(.line) { | ||
display: flex; | ||
gap: 1em; | ||
margin: 0.5em 0; | ||
} | ||
:global(.tei-cb) { | ||
@apply text-right mr-2; | ||
} | ||
:global(.tei-cb:not(.tei-cb:first-child)) { | ||
@apply border-primary-300 border-solid border-t-4; | ||
} | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters