mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-26 22:43:06 -04:00
226 lines
7.5 KiB
Vue
226 lines
7.5 KiB
Vue
<script setup lang="ts">
|
|
import { useNuxtApp } from 'nuxt/app';
|
|
|
|
import useConfig from '~/composables/useConfig.ts';
|
|
import useSimpleHead from '~/composables/useSimpleHead.ts';
|
|
import { ExampleCategory, SourceLibrary } from '~/src/classes.ts';
|
|
import type { Pronoun } from '~/src/classes.ts';
|
|
import { loadPronounExamples, loadPronounLibrary } from '~/src/data.ts';
|
|
|
|
const props = defineProps<{
|
|
pronoun: Pronoun;
|
|
showSources?: boolean;
|
|
}>();
|
|
|
|
const { $translator: translator } = useNuxtApp();
|
|
const config = useConfig();
|
|
|
|
const [pronounLibrary, pronounExamples] = await Promise.all([loadPronounLibrary(config), loadPronounExamples()]);
|
|
|
|
const glue = ` ${translator.translate('pronouns.or')} `;
|
|
|
|
useSimpleHead({
|
|
title: `${translator.translate('pronouns.intro')}: ${props.pronoun.name(glue)}`,
|
|
description: [
|
|
translator.translate('pronouns.examples.header', {}, false),
|
|
translator.translate('pronouns.grammarTable', {}, false),
|
|
translator.translate('sources.headerLong', {}, false),
|
|
].filter((x) => !!x).join(', '),
|
|
banner: `api/banner/${props.pronoun.canonicalName}.png`,
|
|
}, translator);
|
|
|
|
const { data: sources } = useFetch('/api/sources', { lazy: true });
|
|
|
|
const exampleCategories = ExampleCategory.from(pronounExamples, config);
|
|
const nameOptions = props.pronoun.nameOptions();
|
|
const pronounGroup = pronounLibrary.find(props.pronoun);
|
|
|
|
const comprehensive = useComprehensive();
|
|
|
|
const sourceLibrary = computed(() => {
|
|
if (sources.value === null) {
|
|
return null;
|
|
}
|
|
return new SourceLibrary(config, sources.value);
|
|
});
|
|
const groupedSources = computed(() => {
|
|
if (sourceLibrary.value === null || !props.showSources) {
|
|
return {};
|
|
}
|
|
|
|
let key = props.pronoun.canonicalName;
|
|
if (config.sources.enabled && config.sources.mergePronouns[key] !== undefined) {
|
|
key = config.sources.mergePronouns[key];
|
|
}
|
|
return sourceLibrary.value.getForPronounExtended(key);
|
|
});
|
|
|
|
const addSlash = (link: string) => {
|
|
return link + (['*', '\''].includes(link.substr(link.length - 1)) ? '/' : '');
|
|
};
|
|
|
|
const counter = ref(0);
|
|
const counterHandle = ref<number | undefined>();
|
|
const counterSpeed = ref(3000);
|
|
|
|
const setCounterInterval = () => {
|
|
if (counterHandle.value) {
|
|
clearInterval(counterHandle.value);
|
|
}
|
|
if (counterSpeed.value > 0) {
|
|
counter.value++;
|
|
counterHandle.value = setInterval((_) => counter.value++, counterSpeed.value);
|
|
}
|
|
};
|
|
|
|
watch(counterSpeed, () => setCounterInterval());
|
|
onMounted(() => setCounterInterval());
|
|
|
|
const counterPause = () => {
|
|
counterSpeed.value = 0;
|
|
};
|
|
const counterSlow = () => {
|
|
counterSpeed.value = 3000;
|
|
};
|
|
const counterFast = () => {
|
|
counterSpeed.value = 1000;
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<h2
|
|
class="d-flex justify-content-between align-items-start align-items-md-center
|
|
flex-column flex-md-row gap-2"
|
|
>
|
|
<div>
|
|
<Icon v="tag" />
|
|
<T>pronouns.intro</T><T>quotation.colon</T>
|
|
</div>
|
|
<ComprehensiveSwitch v-model="comprehensive" />
|
|
<div v-if="nameOptions.length > 1" class="btn-group" role="group">
|
|
<button
|
|
type="button"
|
|
:class="['btn btn-sm', counterSpeed === 0 ? 'btn-primary' : 'btn-outline-primary']"
|
|
@click="counterPause"
|
|
>
|
|
<Icon v="pause" />
|
|
</button>
|
|
<button
|
|
type="button"
|
|
:class="['btn btn-sm', counterSpeed === 3000 ? 'btn-primary' : 'btn-outline-primary']"
|
|
@click="counterSlow"
|
|
>
|
|
<Icon v="play" />
|
|
</button>
|
|
<button
|
|
type="button"
|
|
:class="['btn btn-sm', counterSpeed === 1000 ? 'btn-primary' : 'btn-outline-primary']"
|
|
@click="counterFast"
|
|
>
|
|
<Icon v="forward" />
|
|
</button>
|
|
</div>
|
|
</h2>
|
|
|
|
<section>
|
|
<div class="alert alert-primary">
|
|
<h2 class="text-center mb-0">
|
|
<template v-if="nameOptions.length === 1">
|
|
<strong><Spelling escape :text="pronoun.name(glue)" /></strong><small v-if="pronoun.smallForm">/<Spelling :text="pronoun.morphemes[pronoun.smallForm] ?? ''" /></small>
|
|
</template>
|
|
<template v-else>
|
|
<template v-for="(nameOption, i) in nameOptions">
|
|
<nuxt-link :to="`/${addSlash(nameOption)}`">
|
|
<strong>
|
|
<Spelling :text="nameOption" escape />
|
|
</strong>
|
|
</nuxt-link>
|
|
<span v-if="i < nameOptions.length - 1"><Spelling :text="glue" /></span>
|
|
</template>
|
|
</template>
|
|
</h2>
|
|
<p v-if="pronoun.description" class="h6 small text-center mb-0 mt-2">
|
|
<em>
|
|
(<LinkedText
|
|
escape
|
|
noicons
|
|
:text="Array.isArray(pronoun.description)
|
|
? `${$t('pronouns.alt.header')}: ${pronoun.description.join(glue)}`
|
|
: pronoun.description"
|
|
/>)
|
|
</em>
|
|
</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<h2 class="h4">
|
|
<Icon v="file-signature" />
|
|
<T>pronouns.examples.header</T><T>quotation.colon</T>
|
|
</h2>
|
|
|
|
<ul>
|
|
<template v-for="exampleCategory in exampleCategories">
|
|
<ExampleCategoryListItem
|
|
v-if="!exampleCategory.comprehensive || comprehensive"
|
|
:example-category="exampleCategory"
|
|
:pronouns-choice="[pronoun]"
|
|
:counter="counter"
|
|
show-pronunciation
|
|
/>
|
|
</template>
|
|
</ul>
|
|
</section>
|
|
|
|
<CensusStat type="pronouns" :item="pronoun.name(glue)" colour="info" />
|
|
|
|
<section v-if="pronoun.history">
|
|
<template v-for="part in pronoun.history.replace(/\\@/g, '###').split('@')">
|
|
<template v-if="part === '__generator__'">
|
|
<div v-if="config.pronouns.generator?.disclaimer ?? true" class="alert alert-warning">
|
|
<Icon v="exclamation-triangle" />
|
|
<T>pronouns.generated</T>
|
|
</div>
|
|
</template>
|
|
<div v-else class="alert alert-light">
|
|
<Icon v="info-circle" />
|
|
<LinkedText :text="part.replace(/###/g, '@')" noicons />
|
|
</div>
|
|
</template>
|
|
</section>
|
|
|
|
<AdPlaceholder :phkey="['content-0', 'content-mobile-0']" />
|
|
|
|
<PronounsGrammarTables :pronoun :counter :comprehensive :pronoun-examples />
|
|
|
|
<AdPlaceholder :phkey="['content-1', 'content-mobile-1']" />
|
|
|
|
<PronounGroup
|
|
v-if="pronounGroup"
|
|
:pronoun-group="pronounGroup.group"
|
|
:pronouns="pronounGroup.groupPronouns"
|
|
/>
|
|
|
|
<Avoiding v-if="pronoun.nullPronoun" />
|
|
|
|
<section>
|
|
<Share :title="`${$t('pronouns.intro')}: ${pronoun.name(glue)}`" />
|
|
</section>
|
|
|
|
<section v-if="Object.values(groupedSources).filter(x => !!x).length">
|
|
<Literature :pronoun="pronoun" :sources="groupedSources" />
|
|
</section>
|
|
|
|
<AdPlaceholder :phkey="['content-2', 'content-mobile-2']" />
|
|
|
|
<Separator icon="info" />
|
|
<section class="mb-0">
|
|
<h2 class="h4">
|
|
<Icon v="info-circle" />
|
|
<T>home.whatisit</T>
|
|
</h2>
|
|
<T>home.about</T>
|
|
<Homepage align="center" />
|
|
</section>
|
|
</template>
|