PronounsPage/components/Declension.vue

92 lines
2.8 KiB
Vue

<template>
<span class="position-relative">
<template v-if="declensionTemplate">
<a v-if="!open" href="#" :class="tooltip && visible ? 'fw-bold' : ''" @click.prevent="visible = !visible"><Spelling :text="word" /></a>
<ul v-if="visible" :class="['list-unstyled', 'small', open ? '' : 'm-2 p-3 pe-5 border bg-light', tooltip ? 'tooltip' : '']">
<li v-for="(declined, c) in declensionTemplate.decline(word, plural)" class="text-nowrap">
<strong>{{ c }} <small v-if="!condense">({{ cases[c] }})</small></strong> {{ declined.join(' / ') }}
</li>
<li v-if="tooltip" class="close"><a href="#" @click.prevent="visible = false"><Icon v="times" /></a></li>
</ul>
</template>
<Spelling v-else :text="word" />
</span>
</template>
<script>
import { nounDeclensionTemplates } from '../src/data.ts';
import cases from '../data/nouns/cases.js';
export default {
props: {
word: { required: true },
plural: { type: Boolean },
singularOptions: { },
template: { },
open: { type: Boolean },
condense: { type: Boolean },
tooltip: { type: Boolean },
},
data() {
return {
declensionTemplate: this.template || this.findTemplate(),
cases,
visible: this.open,
};
},
watch: {
template() {
this.declensionTemplate = this.template || this.findTemplate();
},
},
methods: {
findTemplate() {
let longestMatch = 0;
let templates = [];
for (const t of nounDeclensionTemplates) {
const matchLength = t.matches(this.word, this.plural);
if (matchLength === 0) {
continue;
}
if (matchLength > longestMatch) {
longestMatch = matchLength;
templates = [t];
} else if (matchLength === longestMatch) {
templates.push(t);
}
}
if (!templates.length) {
return null;
} else if (templates.length === 1) {
return templates[0];
} else if (this.plural && this.singularOptions) {
for (const t of templates) {
for (const s of this.singularOptions) {
if (t.matches(s)) {
return t;
}
}
}
}
return templates[0];
},
},
};
</script>
<style lang="scss" scoped>
ul.tooltip {
position: absolute;
top: 1rem;
left: 0;
z-index: 999;
li.close {
position: absolute;
top: 1rem;
right: 1rem;
}
}
</style>