mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-24 05:05:20 -04:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
3e32c16658
@ -3,9 +3,9 @@
|
||||
needs: []
|
||||
rules:
|
||||
-
|
||||
if: $CI_COMMIT_REF_PROTECTED && $DEPLOY_TARGET =~ $ENVIRONMENT_PATTERN
|
||||
if: $CI_COMMIT_REF_PROTECTED == 'true' && $DEPLOY_TARGET =~ $ENVIRONMENT_PATTERN
|
||||
-
|
||||
if: $CI_COMMIT_REF_PROTECTED
|
||||
if: $CI_COMMIT_REF_PROTECTED == 'true'
|
||||
when: manual
|
||||
image: node:20.12.2
|
||||
before_script:
|
||||
|
@ -1,66 +1,61 @@
|
||||
<script setup lang="ts">
|
||||
const { $translator: translator } = useNuxtApp();
|
||||
|
||||
const { data: circleMentions } = useFetch<Record<string, Record<string, string>>>(
|
||||
'/api/profile/my-circle-mentions',
|
||||
{ lazy: true },
|
||||
);
|
||||
|
||||
const dialogue = useDialogue();
|
||||
const removeSelf = async (username: string) => {
|
||||
await dialogue.confirm(translator.translate('profile.circles.removeSelf.confirm', { username }), 'warning');
|
||||
await dialogue.postWithAlertOnError(`/api/profile/remove-self-circle/${encodeURIComponent(username)}`);
|
||||
window.location.reload();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Loading :value="circleMentions">
|
||||
<p class="small text-muted">
|
||||
<T>profile.circles.yourMentions.description</T>
|
||||
</p>
|
||||
<table class="table table-striped table-bordered">
|
||||
<tr v-if="!circleMentions || Object.keys(circleMentions).length === 0">
|
||||
<td class="text-center">
|
||||
<T>table.empty</T>
|
||||
</td>
|
||||
</tr>
|
||||
<template v-else>
|
||||
<template v-for="(profiles, username) in circleMentions">
|
||||
<tr v-if="username !== 'null'">
|
||||
<th>
|
||||
<LocaleLink :link="`/@${username}`" locale="_">
|
||||
@{{ username }}
|
||||
</LocaleLink>
|
||||
</th>
|
||||
<td>
|
||||
<ul>
|
||||
<template v-for="(relationship, locale) in profiles">
|
||||
<li v-if="locale && $locales[locale]">
|
||||
<LocaleLink :link="`/@${username}`" :locale="locale">
|
||||
{{ $locales[locale].name }}
|
||||
</LocaleLink><T>quotation.colon</T>
|
||||
{{ relationship }}
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</td>
|
||||
<td style="max-width: 4rem">
|
||||
<button class="btn btn-link btn-sm text-danger" @click="removeSelf(username)">
|
||||
<Icon v="trash" />
|
||||
<T>profile.circles.removeSelf.action</T>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tbody>
|
||||
<tr v-if="!circleMentions || Object.keys(circleMentions).length === 0">
|
||||
<td class="text-center">
|
||||
<T>table.empty</T>
|
||||
</td>
|
||||
</tr>
|
||||
<template v-else>
|
||||
<template v-for="(profiles, username) in circleMentions" :key="username">
|
||||
<tr v-if="username !== 'null'">
|
||||
<th>
|
||||
<LocaleLink :link="`/@${username}`" locale="_">
|
||||
@{{ username }}
|
||||
</LocaleLink>
|
||||
</th>
|
||||
<td>
|
||||
<ul>
|
||||
<template v-for="(relationship, locale) in profiles" :key="locale">
|
||||
<li v-if="locale && $locales[locale]">
|
||||
<LocaleLink :link="`/@${username}`" :locale="locale">
|
||||
{{ $locales[locale].name }}
|
||||
</LocaleLink><T>quotation.colon</T>
|
||||
{{ relationship }}
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</td>
|
||||
<td style="max-width: 4rem">
|
||||
<button class="btn btn-link btn-sm text-danger" @click="removeSelf(username)">
|
||||
<Icon v="trash" />
|
||||
<T>profile.circles.removeSelf.action</T>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</Loading>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useFetch } from 'nuxt/app';
|
||||
|
||||
import useDialogue from '../composables/useDialogue.ts';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const { data: circleMentions } = useFetch('/api/profile/my-circle-mentions', { lazy: true });
|
||||
return {
|
||||
circleMentions,
|
||||
dialogue: useDialogue(),
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async removeSelf(username) {
|
||||
await this.dialogue.confirm(this.$t('profile.circles.removeSelf.confirm', { username }), 'warning');
|
||||
await this.dialogue.postWithAlertOnError(`/api/profile/remove-self-circle/${encodeURIComponent(username)}`);
|
||||
window.location.reload();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -6,10 +6,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DateLocal from '../data/calendar/DateLocal.vue';
|
||||
|
||||
export default {
|
||||
components: { DateLocal },
|
||||
components: { DateLocal: useLocaleComponent('calendar', 'DateLocal') },
|
||||
props: {
|
||||
day: { required: true },
|
||||
inline: { type: Boolean },
|
||||
|
@ -35,7 +35,7 @@ const formattedPronounName = computed(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a :href="`${base}/${pronounWithoutDomain}`" class="badge bg-primary text-white mx-1">
|
||||
<span class="badge bg-primary text-white mx-1">
|
||||
{{ formattedPronounName }}
|
||||
</a>
|
||||
</span>
|
||||
</template>
|
||||
|
@ -224,7 +224,6 @@ import { mapState } from 'pinia';
|
||||
import type { RouteLocationRaw } from 'vue-router';
|
||||
|
||||
import useConfig from '../composables/useConfig.ts';
|
||||
import NounsNav from '../data/nouns/NounsNav.vue';
|
||||
import forbidden from '../src/forbidden.ts';
|
||||
import type { User } from '../src/user.ts';
|
||||
import { useMainStore } from '../store/index.ts';
|
||||
@ -243,7 +242,7 @@ type HeaderLink = HeaderTo & {
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
components: { NounsNav },
|
||||
components: { NounsNav: useLocaleComponent('nouns', 'NounsNav') },
|
||||
setup() {
|
||||
const hoverItem = ref<HeaderLink | null>(null);
|
||||
return {
|
||||
|
@ -1,10 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<AdPlaceholder phkey="content-footer" />
|
||||
<section>
|
||||
<ShopifyEmbed />
|
||||
</section>
|
||||
</div>
|
||||
<AdPlaceholder phkey="content-footer" />
|
||||
<section v-bind="$attrs">
|
||||
<ShopifyEmbed />
|
||||
</section>
|
||||
|
||||
<!--
|
||||
<section>
|
||||
|
11
composables/useLocaleComponent.ts
Normal file
11
composables/useLocaleComponent.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export default (module: string, componentName: string) => {
|
||||
const config = useConfig();
|
||||
|
||||
return defineAsyncComponent(async () => {
|
||||
try {
|
||||
return await import(`~/locale/${config.locale}/${module}/${componentName}.vue`);
|
||||
} catch (error) {
|
||||
return () => {};
|
||||
}
|
||||
});
|
||||
};
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -761,7 +761,7 @@ workshops:
|
||||
Currently, we offer training and workshops <strong>online</strong>,
|
||||
as well as in person in the Poland, Netherlands and UK (with reimbursement of travel costs); in English and in Polish.
|
||||
- >
|
||||
If you are interested, send us an email to <strong>{mailto:workshops@pronouns.page=workshops@pronouns.page}</strong>,
|
||||
If you are interested, send us an email to {mailto:workshops@pronouns.page=workshops@pronouns.page},
|
||||
remembering to provide information such as: type of organization, location, preferred date and form,
|
||||
expected number of participants, which issues you would like to focus on, etc.
|
||||
- >
|
||||
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1414,7 +1414,7 @@ workshops:
|
||||
Oferujemy szkolenia i warsztaty <strong>na terenie Polski</strong> (za zwrotem ewentualnych kosztów dojazdu),
|
||||
a także <strong>online</strong>; w języku polskim i angielskim.
|
||||
- >
|
||||
Jeśli jesteś zainteresowanx, podeślij nam maila na adres <strong>{mailto:szkolenia@zaimki.pl=szkolenia@zaimki.pl}</strong>,
|
||||
Jeśli jesteś zainteresowanx, podeślij nam maila na adres {mailto:szkolenia@zaimki.pl=szkolenia@zaimki.pl},
|
||||
pamiętając o podaniu informacji takich jak: rodzaj organizacji, lokalizacja, preferowany termin i forma,
|
||||
oczekiwana liczba osób mających wziąć udział, na których zagadnieniach chciałxbyś się skupić, itp.
|
||||
- >
|
||||
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -128,6 +128,7 @@ sources:
|
||||
moderation: 'Пропозиції повинні бути схвалені перед публікацією.'
|
||||
key: 'Ключ'
|
||||
keyInfo: 'Ідентифікатор, що використовується для зв’язку джерел з різних мовних версій і зв’язку з словником.'
|
||||
keyInfoConvention: 'В ідеалі: найпростіша форма терміна англійською, в нижньому регістрі.'
|
||||
images: 'Зображення'
|
||||
spoiler: 'Спойлер'
|
||||
otherVersions: 'В інших мовах'
|
||||
@ -793,6 +794,7 @@ profile:
|
||||
removeSelf:
|
||||
action: 'Прибрати себе'
|
||||
confirm: 'Ви впевнені, що хочете прибрати себе з кола @%username%?'
|
||||
add: 'Додайте людей в своє коло'
|
||||
column: 'Колонка'
|
||||
opinions:
|
||||
custom: 'додане користувач_кою:'
|
||||
@ -1358,6 +1360,7 @@ flags:
|
||||
Trigender: 'Триґендерн{adjective}'
|
||||
Trixic: 'Триксичн{adjective}'
|
||||
Two_Spirit: 'Дві душі'
|
||||
Unlabeled: 'Без лейблів'
|
||||
Xenogender: 'Ксеноґендерн{adjective}'
|
||||
|
||||
calendar:
|
||||
@ -1479,6 +1482,7 @@ calendar:
|
||||
trans_history_month: 'Місяць трансгендерної історії'
|
||||
aplatonic_visibility_day: 'День видимості аплатонічних'
|
||||
aromantic_visibility_day: '{https://aromanticvisibilityday.org/=День видимості аромантичних}'
|
||||
aromantic_spectrum_visibility_day: '{https://aromanticspectrumday.net/en/home-english=День видимості аромантичного спектру}'
|
||||
unlabeled_day: 'День видимості людей без ярликів'
|
||||
transition_week: 'Тиждень трансгендерного переходу'
|
||||
black_hiv_awareness_day: 'День обізнаності про ВІЛ та СНІД у темношкірих людей'
|
||||
@ -1851,3 +1855,13 @@ supportBanner:
|
||||
Ось як ви можете допомогти невинним людям {https://supportukrainenow.org=в Україні},
|
||||
{https://www.humanrightscareers.com/issues/charities-helping-civilians-in-palestine/=в Газі} та
|
||||
{https://donate.unhcr.org/int/en/general=інших зонах воєнних конфліктів}.
|
||||
|
||||
form:
|
||||
persistent:
|
||||
present:
|
||||
question: >
|
||||
Здається, у вас є незбережені дані. На вашому девайсі збережено чернетку (%time%). Ви б хотіли її
|
||||
відновити?
|
||||
load: 'Відновити чернетку'
|
||||
abandon: 'Відмовитися від чернетки'
|
||||
saved: 'Чернетка збережена у вашому браузері (%time%)'
|
||||
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,63 +0,0 @@
|
||||
<template>
|
||||
<section>
|
||||
<div class="d-none d-md-inline-flex btn-group btn-block mb-2 w-100">
|
||||
<router-link
|
||||
v-for="{ name, icon, route } in links"
|
||||
:key="name"
|
||||
:to="buildRoute(route)"
|
||||
:class="['btn', isActiveRoute(route) ? 'btn-primary' : 'btn-outline-primary']"
|
||||
>
|
||||
<Icon :v="icon" />
|
||||
<T>nouns.{{ name }}.header</T>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="d-block-force d-md-none btn-group-vertical btn-block mb-2 w-100">
|
||||
<router-link
|
||||
v-for="{ name, icon, route } in links"
|
||||
:key="name"
|
||||
:to="buildRoute(route)"
|
||||
:class="['btn', isActiveRoute(route) ? 'btn-primary' : 'btn-outline-primary']"
|
||||
>
|
||||
<Icon :v="icon" />
|
||||
<T>nouns.{{ name }}.header</T>
|
||||
</router-link>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import useConfig from '~/composables/useConfig.ts';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
return {
|
||||
config: useConfig(),
|
||||
};
|
||||
},
|
||||
data() {
|
||||
const links = [
|
||||
{ name: 'nouns', icon: 'book', route: '' },
|
||||
];
|
||||
|
||||
if (this.config.inclusive.enabled) {
|
||||
links.push({ name: 'inclusive', icon: 'book-heart', route: this.config.inclusive.route });
|
||||
}
|
||||
|
||||
if (this.config.terminology.enabled) {
|
||||
links.push({ name: 'terms', icon: 'flag', route: this.config.terminology.route });
|
||||
}
|
||||
|
||||
return {
|
||||
links,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
buildRoute(route) {
|
||||
return `/${route}`;
|
||||
},
|
||||
isActiveRoute(route) {
|
||||
return decodeURIComponent(this.$route.fullPath).replace(/\/$/, '') === this.buildRoute(route).replace(/\/$/, '');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
@ -1 +0,0 @@
|
||||
<template></template>
|
@ -1,2 +0,0 @@
|
||||
<template>
|
||||
</template>
|
@ -40,10 +40,9 @@ import type Dictionary from '~/components/Dictionary.vue';
|
||||
import useConfig from '~/composables/useConfig.ts';
|
||||
import useSimpleHead from '~/composables/useSimpleHead.ts';
|
||||
import NounsExtra from '~/data/nouns/NounsExtra.vue';
|
||||
import NounsNav from '~/data/nouns/NounsNav.vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: { NounsNav, NounsExtra },
|
||||
components: { NounsNav: useLocaleComponent('nouns', 'NounsNav'), NounsExtra },
|
||||
setup() {
|
||||
definePageMeta({
|
||||
translatedPaths: (config) => translatedPathByConfigModule(config.nouns),
|
||||
|
@ -46,13 +46,13 @@
|
||||
<T>contact.team.credentials.description</T>
|
||||
|
||||
<ul>
|
||||
<li v-for="credential in credentials">
|
||||
<li v-for="credential in credentials" :key="credential.username">
|
||||
<Spelling :text="convertName(credential.credentialsName || credential.teamName)" />
|
||||
<a :href="`https://pronouns.page/@${credential.username}`" class="badge bg-light text-dark border">
|
||||
@{{ credential.username }}
|
||||
</a>
|
||||
<ul>
|
||||
<li v-for="item in credential.credentials">
|
||||
<li v-for="item in credential.credentials" :key="item">
|
||||
<ProfileLink v-if="item.startsWith('https://') || item.startsWith('http://')" :link="item" />
|
||||
<LinkedText v-else :text="item" />
|
||||
</li>
|
||||
@ -145,9 +145,9 @@ interface Admin {
|
||||
username: string;
|
||||
teamName: string;
|
||||
locale: string;
|
||||
credentials: string[];
|
||||
credentialsLevel: number;
|
||||
credentialsName: string;
|
||||
credentials: string[] | null;
|
||||
credentialsLevel: number | null;
|
||||
credentialsName: string | null;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
@ -162,51 +162,43 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
const { $translator: translator } = useNuxtApp();
|
||||
const config = useConfig();
|
||||
|
||||
useSimpleHead({
|
||||
title: translator.translate('contact.team.name'),
|
||||
description: translator.translate('contact.team.description'),
|
||||
}, translator);
|
||||
const { convertName } = useSpelling();
|
||||
|
||||
const { data: membersByLocale } = useAsyncData(async () => {
|
||||
const teamAsyncData = useAsyncData(async () => {
|
||||
const membersByLocaleRaw = await $fetch<Record<string, Admin[]>>('/api/admin/list');
|
||||
return Object.fromEntries(Object.entries(membersByLocaleRaw).filter(([_, members]) => {
|
||||
const membersByLocale = Object.fromEntries(Object.entries(membersByLocaleRaw).filter(([_, members]) => {
|
||||
return members.length > 0;
|
||||
}));
|
||||
|
||||
const credentials = membersByLocale[config.locale]
|
||||
.filter((member) => member.credentials !== null)
|
||||
.toSorted((a, b) => {
|
||||
if (a.credentialsLevel! > b.credentialsLevel!) {
|
||||
return -1;
|
||||
}
|
||||
if (a.credentialsLevel! < b.credentialsLevel!) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return Math.random() > 0.5 ? 1 : -1;
|
||||
});
|
||||
|
||||
return { membersByLocale, credentials };
|
||||
});
|
||||
|
||||
return {
|
||||
config: useConfig(),
|
||||
config,
|
||||
convertName,
|
||||
membersByLocale,
|
||||
membersByLocale: computed(() => teamAsyncData.data.value?.membersByLocale),
|
||||
credentials: computed(() => teamAsyncData.data.value?.credentials),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
credentials(): Admin[] {
|
||||
const r = [];
|
||||
for (const locale in this.membersByLocale) {
|
||||
if (!this.membersByLocale.hasOwnProperty(locale)) {
|
||||
continue;
|
||||
}
|
||||
for (const member of this.membersByLocale[locale]) {
|
||||
if (member.locale === this.config.locale && member.credentials !== null) {
|
||||
r.push(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return r.sort((a, b) => {
|
||||
if (a.credentialsLevel > b.credentialsLevel) {
|
||||
return -1;
|
||||
}
|
||||
if (a.credentialsLevel < b.credentialsLevel) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return Math.random() > 0.5 ? 1 : -1;
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -16,7 +16,7 @@ const isBrowser = (userAgent: string | undefined): boolean => {
|
||||
};
|
||||
|
||||
export default defineEventHandler((event) => {
|
||||
if (process.env.NODE_ENV === 'production' &&
|
||||
if (process.env.DISABLE_SSR &&
|
||||
!event.path.startsWith('/card/@') && !event.path.startsWith('/blog.atom')) {
|
||||
event.context.nuxt = event.context.nuxt ?? {};
|
||||
event.context.nuxt.noSSR = isBrowser(getHeader(event, 'user-agent')) || isHighLoadTime(global.config.locale);
|
||||
|
Loading…
x
Reference in New Issue
Block a user