mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-22 12:03:25 -04:00
289 lines
12 KiB
Vue
289 lines
12 KiB
Vue
<template>
|
|
<div>
|
|
<div class="mb-3 d-flex justify-content-between flex-column flex-md-row">
|
|
<div class="mw-50">
|
|
<div class="text-nowrap d-flex align-items-center">
|
|
<Avatar :user="user" class="me-3" />
|
|
<div>
|
|
<h2>
|
|
@{{ user.username }}
|
|
</h2>
|
|
<p v-if="user.team || profile.teamName || profile.footerName" class="mb-2">
|
|
<nuxt-link :to="`/${$config.contact.team.route}`" class="badge bg-primary text-white">
|
|
<Icon v="collective-logo.svg" class="inverted" />
|
|
<T>contact.team.member</T>
|
|
</nuxt-link>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="flex-grow-1 text-lg-end">
|
|
<slot></slot>
|
|
</div>
|
|
</div>
|
|
|
|
<section class="row">
|
|
<div v-if="hasDescriptionColumn" :class="['col-12', manyFlagsLayout ? '' : 'col-lg-6']">
|
|
<div v-if="profile.description" class="mb-3">
|
|
<p v-for="line in profile.description.split('\n')" class="mb-1" style="word-break: break-word;">
|
|
<Spelling escape :text="line" :markdown="profile.markdown" />
|
|
</p>
|
|
</div>
|
|
<p v-if="profile.age && profile.age >= minAge">
|
|
<Icon v="birthday-cake" />
|
|
<T v-if="$te('profile.age')">profile.age</T><T v-else>profile.birthday</T><T>quotation.colon</T>
|
|
{{ profile.age }}
|
|
</p>
|
|
<Timezone v-if="profile.timezone" :value="profile.timezone" :is-static="isStatic" />
|
|
</div>
|
|
|
|
<div v-if="profile.flags.length || profile.customFlags.length" :class="['col-12', manyFlagsLayout ? '' : 'col-lg-6']">
|
|
<ClientOnly>
|
|
<ExpandableList
|
|
:values="[...profile.flags.filter(flag => allFlags[flag]), ...profile.customFlags]"
|
|
:limit="32"
|
|
:reduced-limit="8"
|
|
class="list-inline"
|
|
item-class="list-inline-item p-1"
|
|
:is-static="isStatic"
|
|
:expand="expandLinks"
|
|
>
|
|
<template #default="s">
|
|
<Flag
|
|
v-if="typeof s.el === 'string'"
|
|
:termkey="allFlags[s.el].display"
|
|
:name="$translateForPronoun(allFlags[s.el].display, mainPronoun)"
|
|
:alt="$t(`flags_alt.${s.el.replace(/'/g, '*').replace(/ /g, '_')}`)"
|
|
:img="`/flags/${s.el}.png`"
|
|
:terms="terms || []"
|
|
:asterisk="allFlags[s.el].asterisk"
|
|
/>
|
|
<Flag
|
|
v-else
|
|
:termkey="s.el.name"
|
|
:name="s.el.name"
|
|
:alt="s.el.alt || ''"
|
|
:img="buildImageUrl(s.el.value, 'flag')"
|
|
:terms="terms || []"
|
|
custom
|
|
:description="s.el.description"
|
|
:customlink="s.el.link"
|
|
/>
|
|
</template>
|
|
</ExpandableList>
|
|
</ClientOnly>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="row">
|
|
<div v-if="profile.names.length" :class="['col-6', mainRowCount === 3 ? 'col-lg-4' : 'col-lg-6']">
|
|
<h3>
|
|
<Icon v="signature" />
|
|
<T>profile.names</T>
|
|
</h3>
|
|
|
|
<ExpandableList :values="profile.names" :limit="16" class="list-unstyled" :is-static="isStatic" :expand="expandLinks">
|
|
<template #default="s">
|
|
<Opinion
|
|
:word="convertName(s.el.value)"
|
|
:opinion="s.el.opinion"
|
|
:escape="false"
|
|
:markdown="profile.markdown"
|
|
:pronunciation="s.el.pronunciation"
|
|
:link="$config.locale === 'tok' && $config.pronouns.enabled ? `${$config.pronouns.prefix}/${s.el.value}` : null"
|
|
:custom-opinions="profile.opinions"
|
|
/>
|
|
</template>
|
|
</ExpandableList>
|
|
</div>
|
|
<div
|
|
v-if="profile.pronouns.length && $config.pronouns.enabled"
|
|
:class="['col-6', mainRowCount === 3 ? 'col-lg-4' : 'col-lg-6']"
|
|
>
|
|
<h3>
|
|
<Icon v="tags" />
|
|
<T>profile.pronouns</T>
|
|
</h3>
|
|
|
|
<ExpandableList :values="pronounOpinions" :limit="16" class="list-unstyled" :is-static="isStatic" :expand="expandLinks">
|
|
<template #default="s">
|
|
<Opinion
|
|
:word="typeof s.el.pronoun === 'string' ? s.el.pronoun : s.el.pronoun.name(glue)"
|
|
:opinion="s.el.opinion"
|
|
:link="`${$config.pronouns.prefix || ''}/${s.el.link}`"
|
|
:custom-opinions="profile.opinions"
|
|
/>
|
|
</template>
|
|
</ExpandableList>
|
|
</div>
|
|
<div v-if="profile.links.length" :class="['col-12', mainRowCount === 3 ? 'col-lg-4' : 'col-lg-6']">
|
|
<h3>
|
|
<Icon v="link" />
|
|
<T>profile.links</T>
|
|
</h3>
|
|
|
|
<ExpandableList :values="profile.links" :limit="16" class="list-unstyled" :is-static="isStatic" :expand="expandLinks">
|
|
<template #default="s">
|
|
<ProfileLink :link="s.el" :expand="isStatic" :verified-links="profile.verifiedLinks || {}" :metadata="profile.linksMetadata[normaliseUrl(s.el)]" />
|
|
</template>
|
|
</ExpandableList>
|
|
</div>
|
|
</section>
|
|
|
|
<section v-if="profile.words.map(w => w.values.length).reduce((a, b) => a + b, 0) > 0" class="clearfix">
|
|
<h3>
|
|
<Icon v="scroll-old" />
|
|
<T>profile.words</T>
|
|
</h3>
|
|
|
|
<div class="row">
|
|
<template v-for="column in profile.words">
|
|
<div v-if="column.values.length" class="col-6 col-lg-3">
|
|
<h4 v-if="column.header" class="h6">
|
|
<Spelling :text="column.header" :markdown="profile.markdown" />
|
|
</h4>
|
|
|
|
<ExpandableList
|
|
:values="column.values"
|
|
:limit="16"
|
|
class="list-unstyled"
|
|
:is-static="isStatic"
|
|
:expand="expandLinks"
|
|
>
|
|
<template #default="s">
|
|
<Opinion
|
|
:word="s.el.value"
|
|
:opinion="s.el.opinion"
|
|
:custom-opinions="profile.opinions"
|
|
:markdown="profile.markdown"
|
|
/>
|
|
</template>
|
|
</ExpandableList>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</section>
|
|
|
|
<section v-if="profile.events.length + profile.customEvents.length > 0 && !isStatic" class="clearfix">
|
|
<h3>
|
|
<Icon v="calendar" />
|
|
<T>profile.calendar.header</T>
|
|
</h3>
|
|
|
|
<PersonalCalendar :year="year" :events="[...profile.events, ...profile.customEvents]" />
|
|
</section>
|
|
|
|
<section v-if="profile.circle.length > 0 && !isStatic" class="clearfix">
|
|
<h3>
|
|
<Icon v="heart-circle" />
|
|
<T>profile.circles.header</T>
|
|
</h3>
|
|
<div class="row">
|
|
<div v-for="connection in profile.circle" class="col-12 col-lg-4 pt-2 pb-2">
|
|
<Avatar :user="connection" :src="connection.avatar" class="float-start me-2" dsize="4rem" />
|
|
<h4>
|
|
<LocaleLink :link="`/@${connection.username}`" :locale="connection.locale">
|
|
@{{ connection.username }}
|
|
</LocaleLink>
|
|
<Tooltip v-if="connection.circleMutual" :text="$t('profile.circles.mutual')" class="small">
|
|
<Icon v="shield-check" set="s" />
|
|
</Tooltip>
|
|
</h4>
|
|
<p>{{ connection.relationship }}</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<OpinionLegend :custom="profile.opinions" :used="usedOpinions" />
|
|
<p v-if="!isStatic && profile.lastUpdate" class="text-muted small text-center">
|
|
<T>profile.lastUpdate</T><T>quotation.colon</T>
|
|
{{ $date($ulidTime(profile.lastUpdate)) }}
|
|
</p>
|
|
</section>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import spelling from '../plugins/spelling.ts';
|
|
import mainPronoun from '../plugins/mainPronoun.ts';
|
|
import { calendar } from '../src/calendar/calendar.ts';
|
|
import { buildFlags } from '../src/flags.ts';
|
|
import { buildImageUrl } from '../src/helpers.ts';
|
|
|
|
export default spelling.extend(mainPronoun).extend({
|
|
props: {
|
|
user: { required: true },
|
|
profile: { required: true },
|
|
terms: { default: null },
|
|
isStatic: { type: Boolean },
|
|
expandLinks: { type: Boolean },
|
|
},
|
|
data() {
|
|
return {
|
|
allFlags: buildFlags(this.$config.locale),
|
|
glue: ` ${this.$t('pronouns.or')} `,
|
|
minAge: this.$config.ageLimit || 13,
|
|
normaliseUrl: (url) => {
|
|
try {
|
|
return new URL(url).toString();
|
|
} catch {
|
|
return null;
|
|
}
|
|
},
|
|
year: calendar.getCurrentYear(),
|
|
};
|
|
},
|
|
computed: {
|
|
countFlags() {
|
|
return this.profile.flags.length + this.profile.customFlags.length;
|
|
},
|
|
manyFlagsLayout() {
|
|
return this.countFlags > 36 || this.countFlags === 0 || !this.hasDescriptionColumn;
|
|
},
|
|
hasDescriptionColumn() {
|
|
return this.profile.age && this.profile.age > this.minAge ||
|
|
this.profile.description.trim().length ||
|
|
this.profile.team ||
|
|
this.profile.timezone
|
|
;
|
|
},
|
|
mainRowCount() {
|
|
let c = 0;
|
|
if (this.profile.names.length) {
|
|
c++;
|
|
}
|
|
if (this.profile.pronouns.length && this.$config.pronouns.enabled) {
|
|
c++;
|
|
}
|
|
if (this.profile.links.length) {
|
|
c++;
|
|
}
|
|
return c;
|
|
},
|
|
usedOpinions() {
|
|
return new Set([
|
|
...this.profile.names.map((r) => r.opinion),
|
|
...this.profile.pronouns.map((r) => r.opinion),
|
|
...this.profile.words.flat().map((c) => c.values)
|
|
.flat()
|
|
.map((r) => r.opinion),
|
|
]);
|
|
},
|
|
},
|
|
methods: { buildImageUrl },
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.avatar {
|
|
width: 100%;
|
|
max-width: 5rem;
|
|
max-height: 5rem;
|
|
}
|
|
|
|
.mw-50 {
|
|
min-width: 50%;
|
|
}
|
|
</style>
|