mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-08-03 11:07:00 -04:00
95 lines
2.8 KiB
Vue
95 lines
2.8 KiB
Vue
<script setup lang="ts">
|
|
import type { NounDeclension } from '~/src/classes.ts';
|
|
import { loadNounDeclensionTemplates, loadNounsData } from '~/src/data.ts';
|
|
|
|
const props = withDefaults(defineProps<{
|
|
word: string;
|
|
plural?: boolean;
|
|
singularOptions?: string[];
|
|
template?: NounDeclension | null;
|
|
open?: boolean;
|
|
condense?: boolean;
|
|
tooltip?: boolean;
|
|
}>(), {
|
|
plural: false,
|
|
});
|
|
|
|
const [nounsData, nounDeclensionTemplates] = await Promise.all([loadNounsData(), loadNounDeclensionTemplates()]);
|
|
|
|
const visible = ref(props.open);
|
|
|
|
const declensionTemplate = computed(() => {
|
|
return props.template ?? findTemplate();
|
|
});
|
|
|
|
const findTemplate = (): NounDeclension | null => {
|
|
let longestMatch = 0;
|
|
let templates: NounDeclension[] = [];
|
|
for (const t of nounDeclensionTemplates) {
|
|
const matchLength = t.matches(props.word, props.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 (props.plural && props.singularOptions) {
|
|
for (const t of templates) {
|
|
for (const s of props.singularOptions) {
|
|
if (t.matches(s)) {
|
|
return t;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return templates[0];
|
|
};
|
|
</script>
|
|
|
|
<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, caseName) in declensionTemplate.decline(word, plural)"
|
|
:key="caseName"
|
|
class="text-nowrap"
|
|
>
|
|
<strong>
|
|
{{ caseName }}
|
|
<small v-if="!condense">({{ nounsData.cases?.[caseName.toLowerCase()] }})</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>
|
|
|
|
<style lang="scss" scoped>
|
|
ul.tooltip {
|
|
position: absolute;
|
|
top: 1rem;
|
|
left: 0;
|
|
z-index: 999;
|
|
li.close {
|
|
position: absolute;
|
|
top: 1rem;
|
|
right: 1rem;
|
|
}
|
|
}
|
|
</style>
|