PronounsPage/routes/pronoun.vue

252 lines
9.8 KiB
Vue

<template>
<Page>
<NotFound v-if="!selectedPronoun" />
<div v-else>
<h2 class="d-md-flex justify-content-between">
<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 :class="['btn btn-sm', counterSpeed === 0 ? 'btn-primary' : 'btn-outline-primary']" @click="counterPause">
<Icon v="pause" />
</button>
<button :class="['btn btn-sm', counterSpeed === 3000 ? 'btn-primary' : 'btn-outline-primary']" @click="counterSlow">
<Icon v="play" />
</button>
<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="selectedPronoun.name(glue)" /></strong><small v-if="selectedPronoun.smallForm">/<Spelling :text="selectedPronoun.morphemes[selectedPronoun.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="selectedPronoun.description" class="h6 small text-center mb-0 mt-2">
<em>
(<LinkedText
escape
noicons
:text="Array.isArray(selectedPronoun.description)
? `${$t('pronouns.alt.header')}: ${selectedPronoun.description.join(glue)}`
: selectedPronoun.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">
<ExampleCategory
v-if="!exampleCategory.comprehensive || comprehensive"
:example-category="exampleCategory"
:pronouns-choice="[selectedPronoun]"
:counter="counter"
pronunciation
/>
</template>
</ul>
</section>
<CensusStat type="pronouns" :item="selectedPronoun.name(glue)" colour="info" />
<section v-if="selectedPronoun.history">
<template v-for="part in selectedPronoun.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']" />
<GrammarTables :selected-pronoun="selectedPronoun" :comprehensive="comprehensive" :counter="counter" />
<AdPlaceholder :phkey="['content-1', 'content-mobile-1']" />
<PronounGroup :pronoun-group="pronounGroup" />
<Avoiding v-if="isNull" />
<section>
<Share :title="`${$t('pronouns.intro')}: ${selectedPronoun.name(glue)}`" />
</section>
<section v-if="Object.values(groupedSources).filter(x => !!x).length">
<Literature :pronoun="selectedPronoun" :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>
</div>
</Page>
</template>
<script>
import { examples, pronouns, pronounLibrary } from '../src/data.ts';
import { buildPronoun } from '../src/buildPronoun.ts';
import { head } from '../src/helpers.ts';
import GrammarTables from '../data/pronouns/GrammarTables.vue';
import LinkedText from '../components/LinkedText.vue';
import { ExampleCategory, SourceLibrary } from '../src/classes.ts';
export default {
components: { LinkedText, GrammarTables },
async asyncData({ app }) {
return {
sources: await app.$axios.$get('/sources'),
};
},
data() {
const key = this.getPronounKeyFromUrl();
const selectedPronoun = this.$config.pronouns.enabled && key
? buildPronoun(pronouns, key, this.$config, this.$translator)
: null;
return {
exampleCategories: ExampleCategory.from(examples, this.$config),
pronouns,
glue: ` ${this.$t('pronouns.or')} `,
selectedPronoun,
nameOptions: selectedPronoun ? selectedPronoun.nameOptions() : [],
pronounGroup: pronounLibrary.find(selectedPronoun),
counter: 0,
counterHandle: null,
counterSpeed: 1000,
isNull: key && key.startsWith(':'),
};
},
head() {
return this.selectedPronoun
? head({
title: `${this.$t('pronouns.intro')}: ${this.selectedPronoun.name(this.glue)}`,
description: [
this.$t('pronouns.examples.header', {}, false),
this.$t('pronouns.grammarTable', {}, false),
this.$t('sources.headerLong', {}, false),
].filter((x) => !!x).join(', '),
banner: `api/banner${this.$route.path.replace(/\/$/, '')}.png`,
}, this.$translator)
: {};
},
computed: {
comprehensive: {
get() {
return Object.hasOwn(this.$route.query, this.$config.pronouns.comprehensive);
},
set(value) {
if (value === this.comprehensive) {
// prevent warning that $router.replace has no effect
return;
}
const query = structuredClone(this.$route.query);
if (value) {
query[this.$config.pronouns.comprehensive] = null;
} else {
delete query[this.$config.pronouns.comprehensive];
}
this.$router.replace({ query });
},
},
sourceLibrary() {
return new SourceLibrary(this.$config, this.sources);
},
groupedSources() {
if (this.$route.query.hasOwnProperty('nosources')) {
return {};
}
let key = this.selectedPronoun.canonicalName;
if (this.$config.sources.mergePronouns[key] !== undefined) {
key = this.$config.sources.mergePronouns[key];
}
return this.sourceLibrary.getForPronounExtended(key);
},
},
mounted() {
if (process.client) {
this.counterSlow();
}
},
methods: {
getPronounKeyFromUrl() {
let url = this.$route.path;
if (this.$config.pronouns.prefix) {
if (!url.startsWith(this.$config.pronouns.prefix)) {
return null;
}
url = url.substring(this.$config.pronouns.prefix.length);
}
return decodeURIComponent(url.substr(1).replace(/\/$/, ''));
},
addSlash(link) {
return link + (['*', '\''].includes(link.substr(link.length - 1)) ? '/' : '');
},
counterClear() {
if (this.counterHandle) {
clearInterval(this.counterHandle);
}
},
counterPause() {
this.counterSpeed = 0;
this.counterClear();
},
counterSlow() {
this.counterSpeed = 3000;
this.counterClear();
this.counter++;
this.counterHandle = setInterval((_) => this.counter++, this.counterSpeed);
},
counterFast() {
this.counterSpeed = 1000;
this.counterClear();
this.counter++;
this.counterHandle = setInterval((_) => this.counter++, this.counterSpeed);
},
},
};
</script>