Skip to content

Commit

Permalink
first version of Fassungsansicht
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Flick committed Nov 4, 2024
1 parent 1610bb7 commit dbe9ce7
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 3 deletions.
8 changes: 8 additions & 0 deletions src/routes/fassungen/[thirties]/+page.js
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;
28 changes: 26 additions & 2 deletions src/routes/fassungen/[thirties]/+page.svelte
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 src/routes/fassungen/[thirties]/FassungenContent.svelte
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>
2 changes: 1 addition & 1 deletion src/routes/fassungen/data/[thirties]/+server.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export async function GET({ params, fetch }) {
);
const teipbData = hyparchetypes.map(async (h) => {
const r = await fetch(
`${teipb}/parts/syn${params.thirties}.xml/json?&view=single&odd=parzival-verse.odd&xpath=//div[@subtype=%27${h.handle.replace('*', '')}%27]`
`${teipb}/parts/syn${params.thirties}.xml/json?&view=single&odd=parzival-verse.odd&xpath=//div[@subtype=%27${h.handle.replace('*', '')}%27 and @type=%27Textteil%27]`
);
if (!r.ok) {
console.log('Failed to fetch tpData', r);
Expand Down
3 changes: 3 additions & 0 deletions src/routes/textzeugen/data/[witnes]/[page]/+server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { api, teipb } from '$lib/constants';

/** @type {import('./$types').RequestHandler} */
export async function GET({ params, fetch }) {
console.log(
`${teipb}/parts/${params.witnes}.xml/json?&view=page&id=${params.page}&odd=parzival-verse.odd`
);
const teipbData = fetch(
`${teipb}/parts/${params.witnes}.xml/json?&view=page&id=${params.page}&odd=parzival-verse.odd`
).then((r) => {
Expand Down

0 comments on commit dbe9ce7

Please sign in to comment.