Skip to content

Commit 572be7d

Browse files
Merge pull request #43 from DHBern/33-devilstable-order-and-labelling
33 Devilstable: order and labelling > looks good to me. I think this allows me not to request a re-review but to merge it immediately. I hope that's fine. :-)
2 parents 58e3b77 + c96a640 commit 572be7d

File tree

12 files changed

+133
-74
lines changed

12 files changed

+133
-74
lines changed

src/lib/data.svelte.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { api } from '$lib/constants';
2+
3+
export const metadata = $state(
4+
fetch(`${api}/json/metadata-nomenclature.json`).then((r) => r.json())
5+
);

src/lib/functions.js

+29-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { api } from '$lib/constants';
1+
import { metadata } from './data.svelte.js';
2+
import { api } from './constants.js';
23

34
/**
45
* Generate all 827 Dreissiger with 1-30 verses for all sigla
56
* @param {boolean} sigla
6-
* @returns {Array<{ sigla?: string, thirties: string, verse?: string }>}
7+
* @returns {Promise<Array<{ sigla?: string, thirties: string, verse?: string }>>}
78
*/
89
export async function generateEntries(sigla) {
910
const { verses } = await fetch(`${api}/json/metadata-ms-verses.json`).then((r) => r.json());
@@ -13,7 +14,7 @@ export async function generateEntries(sigla) {
1314
/** @type {{thirties: string, verse: string}[]} */
1415
let returnArray = [];
1516
let uniqueVerses = new Set();
16-
verses.forEach(({ thirties, verse }) => {
17+
verses.forEach((/** @type {{thirties: string, verse: string}} */ { thirties, verse }) => {
1718
const key = `${thirties}-${verse}`;
1819
if (!uniqueVerses.has(key)) {
1920
uniqueVerses.add(key);
@@ -23,3 +24,28 @@ export async function generateEntries(sigla) {
2324
return returnArray;
2425
}
2526
}
27+
28+
/**@type {{fragments: {handle: String, sigil: String}[], codices: {handle: String, sigil: String}[]}} */
29+
const { fragments, codices } = await metadata;
30+
31+
/**
32+
* @param {string} handle
33+
*/
34+
export function siglaFromHandle(handle) {
35+
if (handle.includes('fr')) {
36+
return fragments.find(({ handle: s }) => s === handle)?.sigil;
37+
} else {
38+
return codices.find(({ handle: s }) => s === handle)?.sigil;
39+
}
40+
}
41+
42+
/**
43+
* @param {string} handle
44+
*/
45+
export function metadataFromHandle(handle) {
46+
if (handle.includes('fr')) {
47+
return fragments.find(({ handle: s }) => s === handle);
48+
} else {
49+
return codices.find(({ handle: s }) => s === handle);
50+
}
51+
}

src/routes/+page.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import { api } from '$lib/constants';
2+
import { metadata } from '$lib/data.svelte.js';
23

34
/** @type {import('./$types').PageLoad} */
45
export async function load({ fetch }) {
5-
const { codices, fragments } = await fetch(`${api}/json/metadata-nomenclature.json`).then((r) =>
6-
r.json()
7-
);
6+
const { codices, fragments } = await metadata;
87
return {
98
tableData: await fetch(`${api}/json/contiguous_ranges.json`).then((res) => res.json()),
109
codices,

src/routes/Detail.svelte

+38-26
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
ZOOM_MINIMUM_WINDOW_SIZE
1212
} from './Devilstable_DEFAULTS.json';
1313
14+
import { siglaFromHandle, metadataFromHandle } from '$lib/functions';
15+
1416
/** @type {{codices: any, width?: number, height?: number,data?: {values: boolean[], label: string}[], selection: {start: number, end: number}}} */
1517
let { codices, width = 400, height = 400, data = [], selection = $bindable() } = $props();
1618
let marginTop = 30;
@@ -141,13 +143,13 @@
141143
};
142144
}
143145
144-
const popupFractions = $state({});
146+
const popupFragments = $state({});
145147
const popupLabels = $state({});
146-
const openPopupFractions = (e, verseNumber) => {
148+
const openPopupFragments = (e, verseNumber) => {
147149
e.preventDefault();
148150
e.stopPropagation();
149151
const reference = e.currentTarget;
150-
const popup = popupFractions[verseNumber];
152+
const popup = popupFragments[verseNumber];
151153
if (popup && reference) {
152154
computePosition(reference, popup, {
153155
placement: 'top'
@@ -207,12 +209,12 @@
207209
)
208210
);
209211
let verse = $derived(Math.floor(y.invert(mousePos[1])));
210-
let manuscript = $derived(
212+
let frValues = $derived(data.find((d) => d.label === 'fr')?.values);
213+
let manuscriptHandles = $derived(
211214
scaleBandInvert(x)(mousePos[0]) === 'fr'
212-
? data.find((d) => d.label === 'fr')?.values[verse - selection.start] || 'fr'
215+
? frValues?.[verse - selection.start] || 'fr'
213216
: scaleBandInvert(x)(mousePos[0])
214217
);
215-
// $inspect(contigousData);
216218
$effect(() => {
217219
d3.select(gy)
218220
.call(
@@ -283,41 +285,51 @@
283285
data-popup="popupVerse"
284286
bind:this={floating}
285287
>
286-
{#if Array.isArray(manuscript)}
288+
<!-- if manuscriptHandles is an array, we create a list of Links, if it if either Fassungen or fr, we just create a paragraph that informs about the verse.-->
289+
{#if Array.isArray(manuscriptHandles)}
287290
<ul>
288-
{#each manuscript as sigla}
291+
{#each manuscriptHandles as mHandle}
289292
<li>
290-
<a href={`${base}/textzeugen/${sigla}/${verse}`} class="hover:text-secondary-900">
291-
{sigla}
292-
{verse}
293+
<!-- These links are not clickable since it's not possible to put the cursor over it, but it might be possible to access the links with ARIA means. -->
294+
<a href={`${base}/textzeugen/${mHandle}/${verse}`} class="hover:text-secondary-900">
295+
{@html siglaFromHandle(mHandle)}: {verse}
293296
</a>
294297
</li>
295298
{/each}
296299
</ul>
300+
{:else if manuscriptHandles === summaryLabel}
301+
<p>Dreißiger {verse}</p>
302+
{:else if manuscriptHandles === 'fr'}
303+
<p>Fragment {verse}</p>
297304
{:else}
298-
<p>{manuscript} {verse}</p>
305+
<p>{@html siglaFromHandle(String(manuscriptHandles))}: {verse}</p>
299306
{/if}
300307
</div>
301-
{#each data.map((d) => d.label) as label}
308+
<!-- clickable popups on column labels -->
309+
{#each data.map((d) => d.label) as handle}
310+
{@const metadata = metadataFromHandle(handle)}
302311
<div
303-
class="card p-1 variant-filled-primary absolute opacity-0 top-0 left-0 w-max"
304-
bind:this={popupLabels[label]}
312+
class="card p-1 variant-filled-primary absolute opacity-0 top-0 left-0 max-w-prose prose"
313+
bind:this={popupLabels[handle]}
305314
>
306-
<p>Hier stehen Erläuterungen zu {label}</p>
315+
<strong class="">{@html metadata?.['info-h1']}</strong>
316+
{@html metadata?.['info-h2']}
317+
{@html metadata?.info}
307318
</div>
308319
{/each}
309-
{#each data.find((d) => d.label === 'fr')?.values || [] as fraction, i}
310-
{#if Array.isArray(fraction)}
320+
<!-- popups for fragments -->
321+
{#each frValues || [] as fragment, i}
322+
{#if Array.isArray(fragment)}
311323
{@const verse = i + selection.start}
312324
<div
313325
class="card p-1 variant-filled-primary top-0 left-0 w-max absolute opacity-0"
314-
bind:this={popupFractions[verse]}
326+
bind:this={popupFragments[verse]}
315327
>
316328
<ul>
317-
{#each fraction as sigla}
329+
{#each fragment as handle}
318330
<li>
319-
<a href={`${base}/textzeugen/${sigla}/${verse}`} class="hover:text-secondary-900">
320-
{sigla}
331+
<a href={`${base}/textzeugen/${handle}/${verse}`} class="hover:text-secondary-900">
332+
{@html siglaFromHandle(handle)}
321333
{verse}
322334
</a>
323335
</li>
@@ -347,7 +359,7 @@
347359
{#if values}
348360
{#if isNaN(values[1])}
349361
{@const verseNumber = i + selection.start}
350-
{#if values.length === 1}
362+
{#if values?.lenth === 1}
351363
<a
352364
href={`${base}/textzeugen/${values[0]}/${verseNumber}`}
353365
aria-label={`${values[0]}.${verseNumber}`}
@@ -367,13 +379,13 @@
367379
role="button"
368380
tabindex="0"
369381
href="#"
370-
onkeydown={(e) => openPopupFractions(e, verseNumber)}
382+
onkeydown={(e) => openPopupFragments(e, verseNumber)}
371383
onclick={(e) => {
372-
openPopupFractions(e, verseNumber);
384+
openPopupFragments(e, verseNumber);
373385
}}
374386
aria-label={`Mehrere Fr in Vers ${verseNumber}`}
375387
onblur={() => {
376-
popupFractions[verseNumber].style.opacity = '0';
388+
popupFragments[verseNumber].style.opacity = '0';
377389
}}
378390
>
379391
<rect

src/routes/Devilstable.svelte

+20-19
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import {
77
DATA_MAX,
88
BRUSH_WINDOW_DEFAULT_START,
9-
BRUSH_WINDOW_DEFAULT_END
9+
BRUSH_WINDOW_DEFAULT_END,
10+
SIGLA_ORDER
1011
} from './Devilstable_DEFAULTS.json';
1112
const brushDimension = 200;
1213
const brushDimensionWithSafetyPixel = brushDimension + 1; // fixes a glitch, where Brush and Detail don't fit next to each other on PageResize.
@@ -15,43 +16,43 @@
1516
let { codices, width = 400, height = 400, data = [] } = $props();
1617
1718
let mobile = $derived(width < 800);
18-
const defaultChips = [summaryLabel, ...codices.map((c) => c.sigil), 'fr'];
19+
const defaultChips = [summaryLabel, ...SIGLA_ORDER, 'fr'];
1920
let inputChipValues = $state(defaultChips);
2021
let inputChipValueLabels = $derived(
2122
inputChipValues.map((v) => codices.find((c) => c.sigil === v)?.handle ?? v)
2223
);
23-
let fractions = $derived(data.filter((d) => d.label.includes('fr')));
24+
let fragments = $derived(data.filter((d) => d.label.includes('fr')));
2425
/** @type {{label: string, values: boolean[]}} */
25-
let allFractionData = $derived.by(() => {
26+
let allFragmentData = $derived.by(() => {
2627
if (!inputChipValueLabels.includes('fr')) return {};
27-
//combine all the fractions into one Object with the label 'fr'
28+
//combine all the fragments into one Object with the label 'fr'
2829
/** @type {{label: string, values: boolean[]}} */
29-
let fractionData = {
30+
let fragmentData = {
3031
label: 'fr',
3132
values: new Array(DATA_MAX).fill(false)
3233
};
33-
//loop DATA_MAX times and check if the value is in any of the fractions
34+
//loop DATA_MAX times and check if the value is in any of the fragments
3435
for (let i = 0; i < DATA_MAX; i++) {
35-
//check if the value is in any of the fractions
36-
for (let j = 0; j < fractions.length; j++) {
37-
//check if the value is in the range of the fraction
38-
if (fractions[j].values.some(([start, end]) => i + 1 >= start && i + 1 <= end)) {
39-
//if the value is in the range of the fraction, add the label to the array
40-
if (Array.isArray(fractionData.values[i])) {
41-
fractionData.values[i] = [...fractionData.values[i], fractions[j].label];
36+
//check if the value is in any of the fragments
37+
for (let j = 0; j < fragments.length; j++) {
38+
//check if the value is in the range of the fragment
39+
if (fragments[j].values.some(([start, end]) => i + 1 >= start && i + 1 <= end)) {
40+
//if the value is in the range of the fragment, add the label to the array
41+
if (Array.isArray(fragmentData.values[i])) {
42+
fragmentData.values[i] = [...fragmentData.values[i], fragments[j].label];
4243
} else {
43-
fractionData.values[i] = [fractions[j].label];
44+
fragmentData.values[i] = [fragments[j].label];
4445
}
4546
}
4647
}
4748
}
48-
return fractionData;
49+
return fragmentData;
4950
});
5051
/** @type {{label: string, values: boolean[]}[]} */
5152
let boolData = $derived(
5253
inputChipValueLabels.map((c) => {
5354
if (c === 'fr') {
54-
return allFractionData;
55+
return allFragmentData;
5556
} else if (c === summaryLabel) {
5657
return {
5758
label: c,
@@ -111,8 +112,8 @@
111112
whitelist={[
112113
summaryLabel,
113114
'fr',
114-
...codices.map((c) => c.sigil),
115-
...fractions.map((f) => f.label)
115+
...codices.map((/** @type {{ sigil: string; }} */ c) => c.sigil),
116+
...fragments.map((/** @type {{ label: string; }} */ f) => f.label)
116117
]}
117118
bind:value={inputChipValues}
118119
placeholder="Textzeuge / Fragment hinzufügen..."

src/routes/Devilstable_DEFAULTS.json

+20-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,24 @@
55
"BRUSH_WINDOW_DEFAULT_END": 100,
66
"SCROLL_SPEED": 50,
77
"ZOOM_INCREMENT": 40,
8-
"ZOOM_MINIMUM_WINDOW_SIZE": 50
8+
"ZOOM_MINIMUM_WINDOW_SIZE": 50,
9+
"SIGLA_ORDER": [
10+
"D",
11+
"m",
12+
"n",
13+
"o",
14+
"G",
15+
"I",
16+
"O",
17+
"L",
18+
"M",
19+
"Q",
20+
"R",
21+
"T",
22+
"U",
23+
"V",
24+
"V'",
25+
"W",
26+
"Z"
27+
]
928
}

src/routes/einzelverssynopse/[thirties]/[verse]/+page.server.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { api, teipb } from '$lib/constants';
1+
import { teipb } from '$lib/constants';
22
import { generateEntries } from '$lib/functions';
3+
import { metadata } from '$lib/data.svelte.js';
34

45
/** @type {import('./$types').PageServerLoad} */
56
export async function load({ fetch, params }) {
@@ -9,16 +10,15 @@ export async function load({ fetch, params }) {
910
const thirties = params.thirties ?? '1';
1011
const verse = params.verse?.padStart(2, '0') ?? '01';
1112

12-
const sigla = await fetch(`${api}/json/metadata-nomenclature.json`).then((res) => res.json());
1313
// Fetch the textzeugen
14-
sigla.codices.forEach((/** @type {{ handle: string | number; }} */ element) => {
14+
(await metadata).codices.forEach((/** @type {{ handle: string | number; }} */ element) => {
1515
publisherData[element.handle] = fetch(
1616
`${teipb}/parts/${element.handle}.xml/json?odd=parzival.odd&view=page&id=${element.handle}_${thirties}.${verse}`
1717
);
1818
});
1919

2020
// Fetch fassungen
21-
sigla.hyparchetypes.forEach((/** @type {{ handle: string | number; }} */ element) => {
21+
(await metadata).hyparchetypes.forEach((/** @type {{ handle: string | number; }} */ element) => {
2222
publisherData[element.handle] = fetch(
2323
`${teipb}/parts/syn${thirties}.xml/json?odd=parzival.odd&view=single&xpath=//l[@n=%27${element.handle}%20${thirties}.${verse}%27]`
2424
);
@@ -46,7 +46,7 @@ export async function load({ fetch, params }) {
4646
return {
4747
thirties,
4848
verse,
49-
sigla,
49+
metadata,
5050
publisherData: resolvedPublisherDataObject,
5151
loss
5252
};

src/routes/einzelverssynopse/[thirties]/[verse]/+page.svelte

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/** @type {{data: import('./$types').PageData}} */
77
let { data } = $props();
88
9-
let { thirties, verse, sigla, publisherData, loss } = $derived(data);
9+
let { thirties, verse, metadata, publisherData, loss } = $derived(data);
1010
let hyparchetypesSlider = $state(false);
1111
</script>
1212

@@ -16,7 +16,7 @@
1616
<dl class="grid grid-cols-[auto_1fr] justify-between h-fit mb-4 w-fit font-mono">
1717
<dt class="font-bold font-heading-token pr-4">Handschrift</dt>
1818
<dd class="font-bold font-heading-token border-l-2 border-current pl-4">Wortlaut</dd>
19-
{#each sigla.hyparchetypes as archetype (archetype.handle)}
19+
{#each metadata.hyparchetypes as archetype (archetype.handle)}
2020
{#if hyparchetypesSlider}
2121
<dt class="pr-4 py-1 font-sans">{archetype.sigil}</dt>
2222
{#await publisherData[archetype.handle]}
@@ -32,7 +32,7 @@
3232
{#each archetype.witnesses as witness}
3333
{#if publisherData[witness]?.content}
3434
<dt class="pr-4 pt-2 {hyparchetypesSlider ? 'ml-5' : ''}">
35-
{sigla.codices.find((c) => c.handle === witness)?.sigil}
35+
{metadata.codices.find((c) => c.handle === witness)?.sigil}
3636
</dt>
3737
<dd class="border-l-2 border-current {hyparchetypesSlider ? 'ml-5' : ''} pl-4 py-1">
3838
{@html publisherData[witness]?.content}

src/routes/fassungen/data/[thirties]/+server.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { json } from '@sveltejs/kit';
2-
import { api, teipb } from '$lib/constants';
2+
import { teipb } from '$lib/constants';
3+
import { metadata } from '$lib/data.svelte';
34

45
/** @type {import('./$types').RequestHandler} */
56
export async function GET({ params, fetch }) {
6-
const { hyparchetypes } = await fetch(`${api}/json/metadata-nomenclature.json`).then((r) =>
7-
r.json()
8-
);
7+
const { hyparchetypes } = await metadata;
98
const teipbData = hyparchetypes.map(async (h) => {
109
const r = await fetch(
1110
`${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]`

0 commit comments

Comments
 (0)