mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-24 05:05:20 -04:00
(refactor) extract <PronounsCustomGenerator>
This commit is contained in:
parent
cb50f0dbc7
commit
3d4b9c8c26
224
components/pronouns/PronounsCustomGenerator.vue
Normal file
224
components/pronouns/PronounsCustomGenerator.vue
Normal file
@ -0,0 +1,224 @@
|
||||
<script setup lang="ts">
|
||||
import { ExampleCategory, ExamplePart, Pronoun } from '~/src/classes.ts';
|
||||
import Compressor from '~/src/compressor.ts';
|
||||
import { examples, pronounLibrary, pronouns } from '~/src/data.ts';
|
||||
import { addSlash } from '~/src/helpers.ts';
|
||||
import MORPHEMES from '~/data/pronouns/morphemes.ts';
|
||||
|
||||
const config = useConfig();
|
||||
if (!config.pronouns.enabled || !config.pronouns.generator.enabled) {
|
||||
throw new Error('config.pronouns.generator is disabled');
|
||||
}
|
||||
|
||||
const { $translator: translator } = useNuxtApp();
|
||||
const runtimeConfig = useRuntimeConfig();
|
||||
|
||||
const exampleCategories = ExampleCategory.from(examples, config);
|
||||
const examplesByHonorific = [false, true].map((isHonorific) => {
|
||||
const examples = exampleCategories
|
||||
.filter((exampleCategory) => !exampleCategory.comprehensive)
|
||||
.map((exampleCategory) => exampleCategory.examples[0])
|
||||
.filter((example) => example.isHonorific === isHonorific);
|
||||
return { examples, isHonorific };
|
||||
}).filter(({ examples }) => examples.length > 0);
|
||||
|
||||
const open = ref(config.pronouns.generator.autoOpen ?? false);
|
||||
|
||||
const selectedPronoun = ref(pronouns[config.pronouns.default].clone(true));
|
||||
const selectedMorpheme = ref('');
|
||||
|
||||
const glue = ` ${translator.translate('pronouns.or')} `;
|
||||
|
||||
const clearExampleParts = (parts: ExamplePart[]): ExamplePart[] => {
|
||||
return parts.map((p) => new ExamplePart(p.variable, p.str.replace(/^'/, '')));
|
||||
};
|
||||
|
||||
const deduplicatePronounGroup = (pronounGroup: Pronoun[]): Pronoun[] => {
|
||||
const dict: Record<string, Pronoun> = {};
|
||||
for (const pronoun of pronounGroup) {
|
||||
if (Object.hasOwn(dict, pronoun.name(glue))) {
|
||||
continue;
|
||||
}
|
||||
dict[pronoun.name(glue)] = pronoun;
|
||||
}
|
||||
return Object.values(dict);
|
||||
};
|
||||
|
||||
const usedBase = computed((): string | null => {
|
||||
const name = selectedPronoun.value.name(glue);
|
||||
for (const key in pronouns) {
|
||||
if (Object.hasOwn(pronouns, key)) {
|
||||
if (key === name) {
|
||||
return key;
|
||||
}
|
||||
for (const alias of pronouns[key].aliases) {
|
||||
if (alias === name) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
const usedBaseEquals = computed((): boolean => {
|
||||
return !!usedBase.value && selectedPronoun.value.equals(pronouns[usedBase.value], true);
|
||||
});
|
||||
|
||||
const longLink = computed((): string => {
|
||||
const base = pronouns[selectedPronoun.value.morphemes[MORPHEMES[0]]!];
|
||||
|
||||
return base
|
||||
? Compressor.compress(
|
||||
selectedPronoun.value.toArray().map((x) => x.split('|')[0]),
|
||||
base.toArray().map((x) => x.split('|')[0]),
|
||||
).join(',')
|
||||
: selectedPronoun.value.toString();
|
||||
});
|
||||
const link = computed((): string | null => {
|
||||
if (!selectedPronoun.value.pronoun()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const slashes = selectedPronoun.value.toStringSlashes(translator);
|
||||
|
||||
let link;
|
||||
if (usedBaseEquals.value) {
|
||||
link = usedBase.value;
|
||||
} else if (slashes) {
|
||||
link = slashes;
|
||||
} else {
|
||||
link = longLink.value;
|
||||
}
|
||||
|
||||
return addSlash(`${runtimeConfig.public.baseUrl + (config.pronouns.prefix || '')}/${link}`);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<template v-if="config.pronouns.enabled && config.pronouns.generator.enabled">
|
||||
<button v-if="!open" type="button" class="btn btn-outline-primary w-100" @click.prevent="open = true">
|
||||
<Icon v="sliders-h-square" />
|
||||
<T>home.generator.button</T>
|
||||
</button>
|
||||
<div v-else class="card mb-5">
|
||||
<div class="card-header">
|
||||
<Icon v="sliders-h-square" />
|
||||
<T>home.generator.header2</T>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-title border-bottom pb-3">
|
||||
<p><strong><T>home.generator.base</T><T>quotation.colon</T></strong></p>
|
||||
<ul class="list-unstyled">
|
||||
<template v-for="[group, groupPronouns] in pronounLibrary.split()" :key="group.key">
|
||||
<li v-if="!group.hidden">
|
||||
<ul class="list-inline">
|
||||
<li class="list-inline-item">
|
||||
<Spelling :text="group.name" />
|
||||
</li>
|
||||
<template
|
||||
v-for="pronoun in deduplicatePronounGroup(groupPronouns)"
|
||||
:key="pronoun.canonicalName"
|
||||
>
|
||||
<li v-if="!pronoun.hidden" class="list-inline-item">
|
||||
<button
|
||||
:class="['btn', pronoun.name(glue) === selectedPronoun.name(glue) ? 'btn-primary' : 'btn-outline-primary', 'btn-sm', 'my-1']"
|
||||
@click="selectedPronoun = pronoun.clone(true)"
|
||||
>
|
||||
<Spelling :text="pronoun.name(glue)" />
|
||||
</button>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="alert alert-primary">
|
||||
<p class="h3 mb-0 text-center">
|
||||
<Spelling escape :text="selectedPronoun.name(glue)" />
|
||||
<template v-if="config.pronouns.generator.description ?? true">
|
||||
<br>
|
||||
<input
|
||||
v-model="selectedPronoun.description"
|
||||
class="form-control form-input p-0 form-control-sm"
|
||||
:size="selectedPronoun.description.length ? selectedPronoun.description.length + 3 : 16"
|
||||
:maxlength="Pronoun.DESCRIPTION_MAXLENGTH"
|
||||
:placeholder="$t('profile.description')"
|
||||
>
|
||||
</template>
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
<T>pronouns.examples.header</T><T>quotation.colon</T>
|
||||
</p>
|
||||
<template
|
||||
v-for="{ examples: examplesOfHonorific, isHonorific } in examplesByHonorific"
|
||||
:key="isHonorific"
|
||||
>
|
||||
<ul>
|
||||
<li v-for="(example, i) in examplesOfHonorific" :key="i">
|
||||
<template v-for="(part, j) in clearExampleParts(example.parts(selectedPronoun))" :key="j">
|
||||
<input
|
||||
v-if="part.variable"
|
||||
v-model="selectedPronoun.morphemes[part.str]"
|
||||
:class="['form-control form-input p-0', { active: selectedMorpheme === part.str }]"
|
||||
:size="selectedPronoun.morphemes[part.str]?.length ?? 0"
|
||||
maxlength="24"
|
||||
@focus="selectedMorpheme = part.str"
|
||||
@blur="selectedMorpheme = ''"
|
||||
>
|
||||
<span v-else><Spelling :text="part.str" /></span>
|
||||
</template>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-if="config.pronouns.plurals" class="my-3">
|
||||
<div v-if="isHonorific" class="custom-control custom-switch">
|
||||
<input
|
||||
id="pluralHonorific"
|
||||
v-model="selectedPronoun.pluralHonorific[0]"
|
||||
type="checkbox"
|
||||
class="custom-control-input"
|
||||
>
|
||||
<label class="custom-control-label" for="pluralHonorific">
|
||||
<T>pronouns.plural</T>
|
||||
<Icon v="level-up" />
|
||||
</label>
|
||||
</div>
|
||||
<div v-else class="custom-control custom-switch">
|
||||
<input
|
||||
id="plural"
|
||||
v-model="selectedPronoun.plural[0]"
|
||||
type="checkbox"
|
||||
class="custom-control-input"
|
||||
>
|
||||
<label class="custom-control-label" for="plural">
|
||||
<T>pronouns.plural</T>
|
||||
<Icon v="level-up" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<p class="small">
|
||||
<T icon="info-circle">home.generator.alt</T>
|
||||
</p>
|
||||
<!-- TODO #136
|
||||
<p class="small" v-if="config.pronunciation.enabled && $te('home.generator.pronunciation')">
|
||||
<Icon v="info-circle"/>
|
||||
<T>home.generator.pronunciation</T>
|
||||
</p>
|
||||
-->
|
||||
</div>
|
||||
<div v-if="link" class="card-footer">
|
||||
<LinkInput :link="link" />
|
||||
<div
|
||||
v-if="!usedBaseEquals && (config.pronouns.generator.disclaimer ?? true)"
|
||||
class="alert alert-warning"
|
||||
>
|
||||
<Icon v="exclamation-triangle" />
|
||||
<T>pronouns.generated</T>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
@ -41,123 +41,7 @@
|
||||
<p>
|
||||
<T>home.generator.description</T>
|
||||
</p>
|
||||
<a v-if="!customise" href="#" class="btn btn-outline-primary w-100" @click.prevent="customise = true">
|
||||
<Icon v="sliders-h-square" />
|
||||
<T>home.generator.button</T>
|
||||
</a>
|
||||
<div v-else class="card mb-5">
|
||||
<div class="card-header">
|
||||
<Icon v="sliders-h-square" />
|
||||
<T>home.generator.header2</T>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-title border-bottom pb-3">
|
||||
<p><strong><T>home.generator.base</T><T>quotation.colon</T></strong></p>
|
||||
<ul class="list-unstyled">
|
||||
<template v-for="[group, groupPronouns] in pronounLibrary.split()">
|
||||
<li v-if="!group.hidden">
|
||||
<ul class="list-inline">
|
||||
<li class="list-inline-item">
|
||||
<Spelling :text="group.name" />
|
||||
</li>
|
||||
<template v-for="pronoun in deduplicatePronounGroup(groupPronouns)">
|
||||
<li v-if="!pronoun.hidden" class="list-inline-item">
|
||||
<button
|
||||
:class="['btn', pronoun.name(glue) === selectedPronoun.name(glue) ? 'btn-primary' : 'btn-outline-primary', 'btn-sm', 'my-1']"
|
||||
@click="selectedPronoun = pronoun.clone(true)"
|
||||
>
|
||||
<Spelling :text="pronoun.name(glue)" />
|
||||
</button>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="alert alert-primary">
|
||||
<p class="h3 mb-0 text-center">
|
||||
<Spelling escape :text="selectedPronoun.name(glue)" />
|
||||
<template v-if="config.pronouns.generator.description ?? true">
|
||||
<br>
|
||||
<input
|
||||
v-model="selectedPronoun.description"
|
||||
class="form-control form-input p-0 form-control-sm"
|
||||
:size="selectedPronoun.description.length ? selectedPronoun.description.length + 3 : 16"
|
||||
:maxlength="DESCRIPTION_MAXLENGTH"
|
||||
:placeholder="$t('profile.description')"
|
||||
>
|
||||
</template>
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
<T>pronouns.examples.header</T><T>quotation.colon</T>
|
||||
</p>
|
||||
<template v-for="{ examples, isHonorific } in examplesByHonorific">
|
||||
<ul>
|
||||
<li v-for="example in examples">
|
||||
<template v-for="part in clearExampleParts(example.parts(selectedPronoun))">
|
||||
<input
|
||||
v-if="part.variable"
|
||||
v-model="selectedPronoun.morphemes[part.str]"
|
||||
:class="['form-control form-input p-0', { active: selectedMorpheme === part.str }]"
|
||||
:size="selectedPronoun.morphemes[part.str]?.length ?? 0"
|
||||
maxlength="24"
|
||||
@focus="selectedMorpheme = part.str"
|
||||
@blur="selectedMorpheme = ''"
|
||||
>
|
||||
<span v-else><Spelling :text="part.str" /></span>
|
||||
</template>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-if="config.pronouns.plurals" class="my-3">
|
||||
<div v-if="isHonorific" class="custom-control custom-switch">
|
||||
<input
|
||||
id="pluralHonorific"
|
||||
v-model="selectedPronoun.pluralHonorific[0]"
|
||||
type="checkbox"
|
||||
class="custom-control-input"
|
||||
>
|
||||
<label class="custom-control-label" for="pluralHonorific">
|
||||
<T>pronouns.plural</T>
|
||||
<Icon v="level-up" />
|
||||
</label>
|
||||
</div>
|
||||
<div v-else class="custom-control custom-switch">
|
||||
<input
|
||||
id="plural"
|
||||
v-model="selectedPronoun.plural[0]"
|
||||
type="checkbox"
|
||||
class="custom-control-input"
|
||||
>
|
||||
<label class="custom-control-label" for="plural">
|
||||
<T>pronouns.plural</T>
|
||||
<Icon v="level-up" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<p class="small">
|
||||
<T icon="info-circle">home.generator.alt</T>
|
||||
</p>
|
||||
<!-- TODO #136
|
||||
<p class="small" v-if="config.pronunciation.enabled && $te('home.generator.pronunciation')">
|
||||
<Icon v="info-circle"/>
|
||||
<T>home.generator.pronunciation</T>
|
||||
</p>
|
||||
-->
|
||||
</div>
|
||||
<div v-if="link" class="card-footer">
|
||||
<LinkInput :link="link" />
|
||||
<div
|
||||
v-if="!usedBaseEquals && (config.pronouns.generator.disclaimer ?? true)"
|
||||
class="alert alert-warning"
|
||||
>
|
||||
<Icon v="exclamation-triangle" />
|
||||
<T>pronouns.generated</T>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<PronounsCustomGenerator />
|
||||
</li>
|
||||
<li id="multiple" class="list-group-item">
|
||||
<p class="h5">
|
||||
@ -325,12 +209,9 @@
|
||||
<script lang="ts">
|
||||
import { useNuxtApp } from 'nuxt/app';
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { examples, pronouns, pronounLibrary } from '~/src/data.ts';
|
||||
import { pronouns, pronounLibrary } from '~/src/data.ts';
|
||||
import { headerForVariant } from '~/src/buildPronoun.ts';
|
||||
import { ExampleCategory, ExamplePart, Pronoun } from '~/src/classes.ts';
|
||||
import { isEmoji } from '~/src/helpers.ts';
|
||||
import Compressor from '~/src/compressor.ts';
|
||||
import MORPHEMES from '~/data/pronouns/morphemes.ts';
|
||||
import { mapState } from 'pinia';
|
||||
import Suggested from '~/data/pronouns/Suggested.vue';
|
||||
import useConfig from '~/composables/useConfig.ts';
|
||||
@ -350,90 +231,25 @@ export default defineComponent({
|
||||
throw null;
|
||||
}
|
||||
|
||||
const exampleCategories = ExampleCategory.from(examples, config);
|
||||
const examplesByHonorific = [false, true].map((isHonorific) => {
|
||||
const examples = exampleCategories
|
||||
.filter((exampleCategory) => !exampleCategory.comprehensive)
|
||||
.map((exampleCategory) => exampleCategory.examples[0])
|
||||
.filter((example) => example.isHonorific === isHonorific);
|
||||
return { examples, isHonorific };
|
||||
}).filter(({ examples }) => examples.length > 0);
|
||||
|
||||
return {
|
||||
config,
|
||||
|
||||
examplesByHonorific,
|
||||
pronouns,
|
||||
pronounLibrary,
|
||||
|
||||
selectedPronoun: ref(pronouns[config.pronouns.default].clone(true)),
|
||||
selectedMorpheme: ref(''),
|
||||
|
||||
customiseMultiple: ref(false),
|
||||
multiple: ref(config.pronouns.multiple ? config.pronouns.multiple.examples[0].split('&') : []),
|
||||
|
||||
customise: ref(config.pronouns.generator.autoOpen ?? false),
|
||||
|
||||
customiseEmojiPronouns: false,
|
||||
emojiPronounsBase: ref(''),
|
||||
|
||||
glue: ` ${translator.translate('pronouns.or')} `,
|
||||
|
||||
DESCRIPTION_MAXLENGTH: Pronoun.DESCRIPTION_MAXLENGTH,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(useMainStore, [
|
||||
'user',
|
||||
]),
|
||||
usedBase(): string | null {
|
||||
const name = this.selectedPronoun.name(this.glue);
|
||||
for (const key in this.pronouns) {
|
||||
if (this.pronouns.hasOwnProperty(key)) {
|
||||
if (key === name) {
|
||||
return key;
|
||||
}
|
||||
for (const alias of this.pronouns[key].aliases) {
|
||||
if (alias === name) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
usedBaseEquals(): boolean {
|
||||
return !!this.usedBase && this.selectedPronoun.equals(this.pronouns[this.usedBase], true);
|
||||
},
|
||||
longLink(): string {
|
||||
const base = this.pronouns[this.selectedPronoun.morphemes[MORPHEMES[0]]!];
|
||||
|
||||
return base
|
||||
? Compressor.compress(
|
||||
this.selectedPronoun.toArray().map((x) => x.split('|')[0]),
|
||||
base.toArray().map((x) => x.split('|')[0]),
|
||||
).join(',')
|
||||
: this.selectedPronoun.toString();
|
||||
},
|
||||
link(): string | null {
|
||||
if (!this.selectedPronoun.pronoun()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const slashes = this.selectedPronoun.toStringSlashes(this.$translator);
|
||||
|
||||
let link;
|
||||
if (this.usedBaseEquals) {
|
||||
link = this.usedBase;
|
||||
} else if (slashes) {
|
||||
link = slashes;
|
||||
} else {
|
||||
link = this.longLink;
|
||||
}
|
||||
|
||||
return this.addSlash(`${this.$config.public.baseUrl + (this.config.pronouns.prefix || '')}/${link}`);
|
||||
},
|
||||
linkMultiple(): string | null {
|
||||
if (!this.multiple.length) {
|
||||
return null;
|
||||
@ -461,19 +277,6 @@ export default defineComponent({
|
||||
addSlash(link: string): string {
|
||||
return link + (['*', '\''].includes(link.substr(link.length - 1)) ? '/' : '');
|
||||
},
|
||||
clearExampleParts(parts: ExamplePart[]): ExamplePart[] {
|
||||
return parts.map((p) => new ExamplePart(p.variable, p.str.replace(/^'/, '')));
|
||||
},
|
||||
deduplicatePronounGroup(pronounGroup: Pronoun[]): Pronoun[] {
|
||||
const dict: Record<string, Pronoun> = {};
|
||||
for (const pronoun of pronounGroup) {
|
||||
if (dict.hasOwnProperty(pronoun.name(this.glue))) {
|
||||
continue;
|
||||
}
|
||||
dict[pronoun.name(this.glue)] = pronoun;
|
||||
}
|
||||
return Object.values(dict);
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
@ -453,6 +453,10 @@ export const isValidLink = (url: string | URL): boolean => {
|
||||
}
|
||||
};
|
||||
|
||||
export const addSlash = (link: string): string => {
|
||||
return link + (['*', '\''].includes(link.substring(link.length - 1)) ? '/' : '');
|
||||
};
|
||||
|
||||
export const parseUserJwt = (token: string, publicKey: string, allLocalesUrls: string[]): User | null => {
|
||||
try {
|
||||
const parsed = jwt.verify(token, publicKey, {
|
||||
|
Loading…
x
Reference in New Issue
Block a user