PronounsPage/components/GrammarTable.vue
2025-07-27 23:43:57 +02:00

131 lines
6.0 KiB
Vue

<script setup lang="ts">
import { loadGrammarTableVariantsConverter } from '~/src/data.ts';
import type { Example, ExampleValues } from '~/src/language/examples.ts';
import { expandVariantsForSection } from '~/src/language/grammarTables.ts';
import type { GrammarTableDefinition, Variant, SectionDefinition } from '~/src/language/grammarTables.ts';
import { symbolsByNumeri } from '~/src/nouns.ts';
const props = defineProps<{
grammarTable: GrammarTableDefinition;
exampleValues: ExampleValues;
examples?: Example[];
}>();
const variantsFromBaseConverter = await loadGrammarTableVariantsConverter();
const buildVariantsForSection = (
sectionVariants: SectionDefinition['variants'],
): Variant[] => {
return expandVariantsForSection(sectionVariants, variantsFromBaseConverter, props.exampleValues)
.filter((variant) => {
return variant.cells.flatMap((cell) => cell).some((cellPart) => {
return props.exampleValues.morphemeValues.getSpelling(cellPart.morpheme) !== undefined;
});
});
};
const sections = computed(() => {
return props.grammarTable.sections.map((section) => {
const variants = buildVariantsForSection(section.variants);
return { header: section.header, variants };
}).filter((section) => {
return section.variants.length > 0;
});
});
const rowHeaderCount = computed(() => {
return Math.max(...sections.value.map((section) => {
if (!section.header) {
// no row headers at all
return 0;
} else if (!section.variants.some((variant) => variant.name)) {
// all row headers have no variants
return 1;
} else {
// some row headers have variants, needing a column for the icons and for the text
return 3;
}
}));
});
</script>
<template>
<div v-if="sections.length > 0" class="table-responsive">
<table class="table table-sm">
<thead>
<tr>
<th v-if="rowHeaderCount" :colspan="rowHeaderCount"></th>
<th v-for="header in grammarTable.columnHeader" :key="header.name">
<template v-if="header.short">
<Spelling class="d-none d-md-inline" :text="header.name" />
<Tooltip class="d-md-none" :text="header.name">
<Spelling :text="header.short" />
</Tooltip>
</template>
<Spelling v-else :text="header.name" />
</th>
</tr>
</thead>
<tbody>
<template v-for="section in sections">
<tr
v-for="[i, variant] in section.variants.entries()"
:key="`${section.header?.name}-${variant.name}`"
>
<th v-if="i === 0 && rowHeaderCount >= 1" :rowspan="section.variants.length">
<template v-if="section.header">
<template v-if="section.header.short">
<Spelling class="d-none d-md-inline" :text="section.header.name" />
<Tooltip class="d-md-none" :text="section.header.name">
<Spelling :text="section.header.short" />
</Tooltip>
</template>
<Spelling v-else :text="section.header.name" />
</template>
</th>
<template v-if="rowHeaderCount >= 2">
<template v-if="variant.numerus || variant.icon">
<th class="pe-0">
<Tooltip v-if="variant.name" class="text-nowrap" :text="variant.name">
<template v-if="variant.numerus">
{{ symbolsByNumeri[variant.numerus] }}
</template>
<Icon v-if="variant.icon" :v="variant.icon" />
</Tooltip>
</th>
<th class="ps-0">
<Spelling class="d-none d-md-inline" :text="variant.name" />
</th>
</template>
<template v-else>
<th colspan="2">
<Spelling :text="variant.name" />
</th>
</template>
</template>
<td v-for="(cell, index) in variant.cells" :key="index">
<template v-for="(cellPart, cellPartIndex) in cell" :key="cellPartIndex">
<template v-if="cellPartIndex > 0">
/
</template>
<MorphemeWithPronunciation
:morpheme="cellPart.morpheme"
:example-values
:prefix="cellPart.prefix"
:suffix="cellPart.suffix"
:highlights-morphemes="cellPart.highlightsMorphemes"
:examples
/>
</template>
</td>
<td
v-if="grammarTable.columnHeader.length > variant.cells.length"
:colspan="grammarTable.columnHeader.length - variant.cells.length"
></td>
</tr>
</template>
</tbody>
</table>
</div>
</template>