mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-09 07:26:01 -04:00
(ts) migrate some components to composition API with typescript
This commit is contained in:
parent
8959e84889
commit
a70de3d972
@ -1,3 +1,248 @@
|
||||
<script setup lang="ts">
|
||||
import { useCookie, useFetch } from 'nuxt/app';
|
||||
|
||||
import useConfig from '../composables/useConfig.ts';
|
||||
import useDialogue from '../composables/useDialogue.ts';
|
||||
import { longtimeCookieSetting } from '../src/cookieSettings.ts';
|
||||
import { newDate, gravatar } from '../src/helpers.ts';
|
||||
import { socialProviders } from '../src/socialProviders.ts';
|
||||
import { usernameRegex } from '../src/username.ts';
|
||||
import { useMainStore } from '../store/index.ts';
|
||||
|
||||
import { getUrlForLocale, getUrlsForAllLocales } from '~/src/domain.ts';
|
||||
import type { Profile } from '~/src/profile.ts';
|
||||
|
||||
const { $translator: translator, $setToken: setToken, $removeToken: removeToken } = useNuxtApp();
|
||||
const runtimeConfig = useRuntimeConfig();
|
||||
const config = useConfig();
|
||||
|
||||
const dialogue = useDialogue();
|
||||
const { accounts, user } = storeToRefs(useMainStore());
|
||||
|
||||
if (user.value === null) {
|
||||
throw 'no user';
|
||||
}
|
||||
|
||||
const tokenCookie = useCookie('token', longtimeCookieSetting);
|
||||
const impersonatorCookie = useCookie('impersonator');
|
||||
const termsUpdateDismissed3Cookie = useCookie('termsUpdateDismissed3', longtimeCookieSetting);
|
||||
|
||||
const { data: profilesData } = useFetch(`/api/profile/get/${user.value.username}?version=2&props=hide`, {
|
||||
lazy: true,
|
||||
});
|
||||
const { data: socialConnections } = useFetch('/api/user/social-connections', {
|
||||
lazy: true,
|
||||
});
|
||||
|
||||
const baseUrl = getUrlForLocale(config.locale);
|
||||
const universalDomains = getUrlsForAllLocales(config.locale).filter((url) => url !== baseUrl);
|
||||
|
||||
const username = ref(user.value.username);
|
||||
const email = ref(user.value.email);
|
||||
const socialLookup = ref(Boolean(user.value.socialLookup));
|
||||
|
||||
const message = ref('');
|
||||
const messageParams = ref({});
|
||||
const messageIcon = ref<string | null>(null);
|
||||
const error = ref('');
|
||||
const changeEmailAuthId = ref(null);
|
||||
const code = ref<string | null>('');
|
||||
|
||||
const savingUsername = ref(false);
|
||||
const savingEmail = ref(false);
|
||||
|
||||
const showCaptcha = ref(false);
|
||||
const captchaToken = ref(null);
|
||||
|
||||
const logoutInProgress = ref(false);
|
||||
|
||||
const showTermsUpdate = ref(newDate() < new Date(2023, 3, 6) && !termsUpdateDismissed3Cookie.value);
|
||||
|
||||
const profiles = computed(() => profilesData.value?.profiles);
|
||||
const setProfiles = (profiles: Record<string, Partial<Profile>>) => {
|
||||
profilesData.value.profiles = profiles;
|
||||
};
|
||||
|
||||
const impersonationActive = computed(() => {
|
||||
return !!impersonatorCookie.value;
|
||||
});
|
||||
|
||||
const canChangeEmail = computed(() => {
|
||||
return email.value && captchaToken.value;
|
||||
});
|
||||
|
||||
const usernameError = computed(() => {
|
||||
if (!username.value.match(usernameRegex)) {
|
||||
return translator.translate('user.account.changeUsername.invalid');
|
||||
}
|
||||
if (username.value !== encodeURIComponent(username.value)) {
|
||||
return translator.translate('user.account.changeUsername.nonascii', { encoded: encodeURIComponent(username.value) });
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
const hasEmail = computed(() => {
|
||||
return user.value?.email && !user.value.email.endsWith('.oauth');
|
||||
});
|
||||
|
||||
const authMethodsCount = computed(() => {
|
||||
if (!user.value || socialConnections.value === null) {
|
||||
return null;
|
||||
}
|
||||
return Object.keys(socialConnections.value).length + (hasEmail.value ? 1 : 0);
|
||||
});
|
||||
|
||||
watch(email, (v) => {
|
||||
if (v !== user.value?.email) {
|
||||
showCaptcha.value = true;
|
||||
}
|
||||
});
|
||||
watch(socialLookup, async (v) => {
|
||||
const response = await dialogue.postWithAlertOnError<any>('/api/user/set-social-lookup', { socialLookup: v });
|
||||
|
||||
await setToken(response.token);
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
onMounted(async () => {
|
||||
const user = await $fetch('/api/user/current');
|
||||
if (user) {
|
||||
await setToken(user.token);
|
||||
}
|
||||
|
||||
const redirectTo = window.sessionStorage.getItem('after-login');
|
||||
if (user.value && redirectTo) {
|
||||
window.sessionStorage.removeItem('after-login');
|
||||
await router.push(redirectTo);
|
||||
}
|
||||
});
|
||||
|
||||
const changeUsername = async () => {
|
||||
error.value = '';
|
||||
|
||||
if (savingUsername.value || !user.value) {
|
||||
return;
|
||||
}
|
||||
savingUsername.value = true;
|
||||
try {
|
||||
const response = await dialogue.postWithAlertOnError<any>('/api/user/change-username', {
|
||||
username: username.value,
|
||||
});
|
||||
|
||||
if (response.error) {
|
||||
error.value = response.error;
|
||||
return;
|
||||
}
|
||||
|
||||
await removeToken(user.value.username);
|
||||
await setToken(response.token);
|
||||
username.value = user.value.username;
|
||||
message.value = 'crud.saved';
|
||||
messageParams.value = {};
|
||||
messageIcon.value = 'check-circle';
|
||||
setTimeout(() => message.value = '', 3000);
|
||||
} finally {
|
||||
savingUsername.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const codeInput = useTemplateRef('codeInput');
|
||||
const changeEmail = async () => {
|
||||
error.value = '';
|
||||
|
||||
if (savingEmail.value) {
|
||||
return;
|
||||
}
|
||||
savingEmail.value = true;
|
||||
try {
|
||||
const response = await dialogue.postWithAlertOnError<any>('/api/user/change-email', {
|
||||
email: email.value,
|
||||
authId: changeEmailAuthId.value,
|
||||
code: code.value,
|
||||
captchaToken: captchaToken.value,
|
||||
});
|
||||
|
||||
if (response.error) {
|
||||
error.value = response.error;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!changeEmailAuthId.value) {
|
||||
changeEmailAuthId.value = response.authId;
|
||||
message.value = 'user.login.emailSent';
|
||||
messageParams.value = { email: addBrackets(email.value) };
|
||||
messageIcon.value = 'envelope-open-text';
|
||||
await nextTick();
|
||||
codeInput.value?.focus();
|
||||
} else {
|
||||
changeEmailAuthId.value = null;
|
||||
message.value = '';
|
||||
messageParams.value = {};
|
||||
code.value = null;
|
||||
|
||||
await setToken(response.token);
|
||||
message.value = 'crud.saved';
|
||||
messageParams.value = {};
|
||||
messageIcon.value = 'check-circle';
|
||||
setTimeout(() => message.value = '', 3000);
|
||||
}
|
||||
} finally {
|
||||
savingEmail.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
logoutInProgress.value = true;
|
||||
setTimeout(doLogout, 3000);
|
||||
};
|
||||
const logoutAll = () => {
|
||||
window.localStorage.removeItem('account-tokens');
|
||||
logout();
|
||||
};
|
||||
const doLogout = async () => {
|
||||
await removeToken();
|
||||
logoutInProgress.value = false;
|
||||
setTimeout(() => window.location.reload(), 300);
|
||||
};
|
||||
|
||||
const deleteAccount = async () => {
|
||||
await dialogue.confirm(translator.translate('user.deleteAccountConfirm'), 'danger');
|
||||
|
||||
await dialogue.postWithAlertOnError('/api/user/delete');
|
||||
|
||||
if (impersonationActive.value) {
|
||||
stopImpersonation();
|
||||
} else {
|
||||
logout();
|
||||
}
|
||||
};
|
||||
const setAvatar = async (source: string | null) => {
|
||||
const response = await dialogue.postWithAlertOnError<any>('/api/user/set-avatar', { source });
|
||||
|
||||
await setToken(response.token);
|
||||
};
|
||||
const uploaded = async (ids: string[]) => {
|
||||
await setAvatar(`${runtimeConfig.public.cloudfront}/images/${ids[0]}-avatar.png`);
|
||||
};
|
||||
const stopImpersonation = async () => {
|
||||
if (!user.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
await removeToken(user.value.username);
|
||||
tokenCookie.value = impersonatorCookie.value;
|
||||
impersonatorCookie.value = null;
|
||||
setTimeout(() => window.location.reload(), 300);
|
||||
};
|
||||
const dismissTermsUpdate = () => {
|
||||
termsUpdateDismissed3Cookie.value = 'true';
|
||||
showTermsUpdate.value = false;
|
||||
};
|
||||
const addBrackets = (str: string): string => {
|
||||
return str ? `(${str})` : '';
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section v-if="logoutInProgress || !user">
|
||||
<p class="text-center">
|
||||
@ -150,7 +395,7 @@
|
||||
</div>
|
||||
<div v-else class="input-group mb-3">
|
||||
<input
|
||||
ref="code"
|
||||
ref="codeInput"
|
||||
v-model="code"
|
||||
type="text"
|
||||
class="form-control text-center"
|
||||
@ -336,266 +581,6 @@
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useCookie, useFetch } from 'nuxt/app';
|
||||
|
||||
import useConfig from '../composables/useConfig.ts';
|
||||
import useDialogue from '../composables/useDialogue.ts';
|
||||
import { longtimeCookieSetting } from '../src/cookieSettings.ts';
|
||||
import { newDate, gravatar } from '../src/helpers.ts';
|
||||
import { socialProviders } from '../src/socialProviders.ts';
|
||||
import { usernameRegex } from '../src/username.ts';
|
||||
import { useMainStore } from '../store/index.ts';
|
||||
|
||||
import { getUrlForLocale, getUrlsForAllLocales } from '~/src/domain.ts';
|
||||
import type { Profile } from '~/src/profile.ts';
|
||||
|
||||
export default defineComponent({
|
||||
async setup() {
|
||||
const dialogue = useDialogue();
|
||||
const { accounts, user } = storeToRefs(useMainStore());
|
||||
|
||||
if (user.value === null) {
|
||||
throw 'no user';
|
||||
}
|
||||
|
||||
const tokenCookie = useCookie('token', longtimeCookieSetting);
|
||||
const impersonatorCookie = useCookie('impersonator');
|
||||
const termsUpdateDismissed3Cookie = useCookie('termsUpdateDismissed3', longtimeCookieSetting);
|
||||
|
||||
const { data: profilesData } = useFetch(`/api/profile/get/${user.value.username}?version=2&props=hide`, {
|
||||
lazy: true,
|
||||
});
|
||||
const { data: socialConnections } = useFetch('/api/user/social-connections', {
|
||||
lazy: true,
|
||||
});
|
||||
|
||||
const config = useConfig();
|
||||
const baseUrl = getUrlForLocale(config.locale);
|
||||
|
||||
return {
|
||||
config,
|
||||
universalDomains: getUrlsForAllLocales(config.locale).filter((url) => url !== baseUrl),
|
||||
dialogue,
|
||||
user,
|
||||
username: ref(user.value.username),
|
||||
email: ref(user.value.email),
|
||||
socialLookup: ref(Boolean(user.value.socialLookup)),
|
||||
accounts,
|
||||
tokenCookie,
|
||||
impersonatorCookie,
|
||||
termsUpdateDismissed3Cookie,
|
||||
profilesData,
|
||||
socialConnections,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
message: '',
|
||||
messageParams: {},
|
||||
messageIcon: null as string | null,
|
||||
error: '',
|
||||
changeEmailAuthId: null,
|
||||
code: '' as string | null,
|
||||
|
||||
socialProviders,
|
||||
|
||||
savingUsername: false,
|
||||
savingEmail: false,
|
||||
|
||||
gravatar,
|
||||
|
||||
showCaptcha: false,
|
||||
captchaToken: null,
|
||||
|
||||
logoutInProgress: false,
|
||||
|
||||
showTermsUpdate: newDate() < new Date(2023, 3, 6) &&
|
||||
!this.termsUpdateDismissed3Cookie,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
profiles() {
|
||||
return this.profilesData?.profiles;
|
||||
},
|
||||
impersonationActive() {
|
||||
return !!this.impersonatorCookie;
|
||||
},
|
||||
canChangeEmail() {
|
||||
return this.email && this.captchaToken;
|
||||
},
|
||||
usernameError() {
|
||||
if (!this.username.match(usernameRegex)) {
|
||||
return this.$t('user.account.changeUsername.invalid');
|
||||
}
|
||||
if (this.username !== encodeURIComponent(this.username)) {
|
||||
return this.$t('user.account.changeUsername.nonascii', { encoded: encodeURIComponent(this.username) });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
hasEmail() {
|
||||
return this.user?.email && !this.user.email.endsWith('.oauth');
|
||||
},
|
||||
authMethodsCount() {
|
||||
if (!this.user || this.socialConnections === null) {
|
||||
return null;
|
||||
}
|
||||
return Object.keys(this.socialConnections).length + (this.hasEmail ? 1 : 0);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
email(v) {
|
||||
if (v !== this.user?.email) {
|
||||
this.showCaptcha = true;
|
||||
}
|
||||
},
|
||||
async socialLookup(v) {
|
||||
const response = await this.dialogue.postWithAlertOnError<any>('/api/user/set-social-lookup', { socialLookup: v });
|
||||
|
||||
await this.$setToken(response.token);
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
const user = await $fetch('/api/user/current');
|
||||
if (user) {
|
||||
await this.$setToken(user.token);
|
||||
}
|
||||
|
||||
const redirectTo = window.sessionStorage.getItem('after-login');
|
||||
if (this.user && redirectTo) {
|
||||
window.sessionStorage.removeItem('after-login');
|
||||
await this.$router.push(redirectTo);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async changeUsername() {
|
||||
this.error = '';
|
||||
|
||||
if (this.savingUsername || !this.user) {
|
||||
return;
|
||||
}
|
||||
this.savingUsername = true;
|
||||
try {
|
||||
const response = await this.dialogue.postWithAlertOnError<any>('/api/user/change-username', {
|
||||
username: this.username,
|
||||
});
|
||||
|
||||
if (response.error) {
|
||||
this.error = response.error;
|
||||
return;
|
||||
}
|
||||
|
||||
await this.$removeToken(this.user.username);
|
||||
await this.$setToken(response.token);
|
||||
this.username = this.user.username;
|
||||
this.message = 'crud.saved';
|
||||
this.messageParams = {};
|
||||
this.messageIcon = 'check-circle';
|
||||
setTimeout(() => this.message = '', 3000);
|
||||
} finally {
|
||||
this.savingUsername = false;
|
||||
}
|
||||
},
|
||||
async changeEmail() {
|
||||
this.error = '';
|
||||
|
||||
if (this.savingEmail) {
|
||||
return;
|
||||
}
|
||||
this.savingEmail = true;
|
||||
try {
|
||||
const response = await this.dialogue.postWithAlertOnError<any>('/api/user/change-email', {
|
||||
email: this.email,
|
||||
authId: this.changeEmailAuthId,
|
||||
code: this.code,
|
||||
captchaToken: this.captchaToken,
|
||||
});
|
||||
|
||||
if (response.error) {
|
||||
this.error = response.error;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.changeEmailAuthId) {
|
||||
this.changeEmailAuthId = response.authId;
|
||||
this.message = 'user.login.emailSent';
|
||||
this.messageParams = { email: this.addBrackets(this.email) };
|
||||
this.messageIcon = 'envelope-open-text';
|
||||
this.$nextTick(() => {
|
||||
(this.$refs.code as HTMLInputElement).focus();
|
||||
});
|
||||
} else {
|
||||
this.changeEmailAuthId = null;
|
||||
this.message = '';
|
||||
this.messageParams = {};
|
||||
this.code = null;
|
||||
|
||||
await this.$setToken(response.token);
|
||||
this.message = 'crud.saved';
|
||||
this.messageParams = {};
|
||||
this.messageIcon = 'check-circle';
|
||||
setTimeout(() => this.message = '', 3000);
|
||||
}
|
||||
} finally {
|
||||
this.savingEmail = false;
|
||||
}
|
||||
},
|
||||
logout() {
|
||||
this.logoutInProgress = true;
|
||||
setTimeout(this.doLogout, 3000);
|
||||
},
|
||||
logoutAll() {
|
||||
window.localStorage.removeItem('account-tokens');
|
||||
this.logout();
|
||||
},
|
||||
async doLogout() {
|
||||
await this.$removeToken();
|
||||
this.logoutInProgress = false;
|
||||
setTimeout(() => window.location.reload(), 300);
|
||||
},
|
||||
setProfiles(profiles: Record<string, Partial<Profile>>) {
|
||||
this.profiles = profiles;
|
||||
},
|
||||
async deleteAccount() {
|
||||
await this.dialogue.confirm(this.$t('user.deleteAccountConfirm'), 'danger');
|
||||
|
||||
await this.dialogue.postWithAlertOnError('/api/user/delete');
|
||||
|
||||
if (this.impersonationActive) {
|
||||
this.stopImpersonation();
|
||||
} else {
|
||||
this.logout();
|
||||
}
|
||||
},
|
||||
async setAvatar(source: string | null) {
|
||||
const response = await this.dialogue.postWithAlertOnError<any>('/api/user/set-avatar', { source });
|
||||
|
||||
await this.$setToken(response.token);
|
||||
},
|
||||
async uploaded(ids: string[]) {
|
||||
await this.setAvatar(`${this.$config.public.cloudfront}/images/${ids[0]}-avatar.png`);
|
||||
},
|
||||
async stopImpersonation() {
|
||||
if (!this.user) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.$removeToken(this.user.username);
|
||||
this.tokenCookie = this.impersonatorCookie;
|
||||
this.impersonatorCookie = null;
|
||||
setTimeout(() => window.location.reload(), 300);
|
||||
},
|
||||
dismissTermsUpdate() {
|
||||
this.termsUpdateDismissed3Cookie = 'true';
|
||||
this.showTermsUpdate = false;
|
||||
},
|
||||
addBrackets(str: string): string {
|
||||
return str ? `(${str})` : '';
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "assets/variables";
|
||||
|
||||
|
@ -1,5 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
import useConfig from '~/composables/useConfig.ts';
|
||||
import type { Day, Year } from '~/src/calendar/helpers.ts';
|
||||
import { socialLinks } from '~/src/contact.ts';
|
||||
import { getUrlForLocale } from '~/src/domain.js';
|
||||
import { clearUrl, newDate } from '~/src/helpers.ts';
|
||||
|
||||
const props = defineProps<{
|
||||
day?: Day;
|
||||
year?: Year;
|
||||
}>();
|
||||
|
||||
const config = useConfig();
|
||||
|
||||
const bots = [
|
||||
socialLinks.calendar?.mastodon,
|
||||
socialLinks.calendar?.bluesky,
|
||||
].filter((bot) => bot !== undefined);
|
||||
|
||||
const icsLink = computed(() => {
|
||||
if (!props.year) {
|
||||
return undefined;
|
||||
}
|
||||
const yearSuffix = props.year.year === newDate().getFullYear() ? '' : `-${props.year.year}`;
|
||||
return `${getUrlForLocale(config.locale)}/api/queer-calendar-${config.locale}${yearSuffix}.ics`;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section>
|
||||
<section v-if="config.calendar?.enabled">
|
||||
<div class="alert alert-info d-flex flex-column flex-md-row justify-content-around">
|
||||
<div v-if="day" class="px-1">
|
||||
<p class="h5">
|
||||
@ -37,7 +65,7 @@
|
||||
<T>calendar.image.header</T>
|
||||
</a>
|
||||
</p>
|
||||
<p v-else class="mb-0">
|
||||
<p v-else-if="year" class="mb-0">
|
||||
<a
|
||||
:href="`/calendar/${config.locale}/${year.year}-overview.png`"
|
||||
target="_blank"
|
||||
@ -74,38 +102,3 @@
|
||||
</section>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import useConfig from '../composables/useConfig.ts';
|
||||
import { socialLinks } from '../src/contact.ts';
|
||||
import { clearUrl, newDate } from '../src/helpers.ts';
|
||||
|
||||
import { getUrlForLocale } from '~/src/domain.js';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
day: {},
|
||||
year: {},
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
config: useConfig(),
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bots: [
|
||||
socialLinks.calendar.mastodon,
|
||||
socialLinks.calendar.bluesky,
|
||||
],
|
||||
clearUrl,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
icsLink() {
|
||||
const yearSuffix = this.year.year === newDate().getFullYear() ? '' : `-${this.year.year}`;
|
||||
return `${getUrlForLocale(this.config.locale)}/api/queer-calendar-${this.config.locale}${yearSuffix}.ics`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -1,3 +1,57 @@
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
import logoSvg from '~/public/logo/logo.svg?raw';
|
||||
import { Day } from '~/src/calendar/helpers.ts';
|
||||
import { loadCalendar } from '~/src/data.ts';
|
||||
import { ImmutableArray } from '~/src/helpers.ts';
|
||||
import { useMainStore } from '~/store/index.ts';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
flag?: boolean;
|
||||
forceShowFlag?: boolean;
|
||||
day?: Day;
|
||||
}>(), {
|
||||
day: () => Day.today(),
|
||||
});
|
||||
|
||||
const selectedDay = storeToRefs(useMainStore()).selectedDay;
|
||||
const calendar = await loadCalendar();
|
||||
|
||||
const svg = ref(logoSvg.replace('/></svg>', 'fill="currentColor"/></svg>'));
|
||||
const flagName = ref<string | null>(null);
|
||||
const forceShowFlagDyn = ref(false);
|
||||
|
||||
const selectFlag = (): string | null => {
|
||||
const events = calendar.getCurrentYear()!.eventsByDate[(selectedDay.value || props.day).toString()];
|
||||
if (!events) {
|
||||
return null;
|
||||
}
|
||||
return new ImmutableArray(...events)
|
||||
.filter((e) => e.display.type === 'flag' && !e.display.name.startsWith('_'))
|
||||
.sorted((a, b) => b.level - a.level)
|
||||
.groupBy((e) => e.level)
|
||||
.indexOrFallback(0, ['0', new ImmutableArray()])[1]
|
||||
.map((e) => e.display.name)
|
||||
.randomElement();
|
||||
};
|
||||
|
||||
watch(selectedDay, () => {
|
||||
forceShowFlagDyn.value = !!selectedDay.value;
|
||||
// removing the flag from the selected day is deferred until the transition has finished
|
||||
// so that it does not suddenly change
|
||||
if (selectedDay.value !== null) {
|
||||
flagName.value = selectFlag();
|
||||
}
|
||||
});
|
||||
|
||||
const resetFlagIfNotOverwritten = (): void => {
|
||||
if (selectedDay.value === null) {
|
||||
flagName.value = selectFlag();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span
|
||||
v-if="flag"
|
||||
@ -10,76 +64,6 @@
|
||||
<span v-else :class="['logo', $attrs.class]" v-html="svg"></span>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
import logoSvg from '../public/logo/logo.svg?raw';
|
||||
import { Day } from '../src/calendar/helpers.ts';
|
||||
import { loadCalendar } from '../src/data.ts';
|
||||
import { ImmutableArray } from '../src/helpers.ts';
|
||||
import { useMainStore } from '../store/index.ts';
|
||||
|
||||
interface Data {
|
||||
svg: string;
|
||||
flagName: string | null;
|
||||
forceShowFlagDyn: boolean;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
flag: { type: Boolean },
|
||||
forceShowFlag: { type: Boolean },
|
||||
day: { default: () => Day.today(), type: Day },
|
||||
},
|
||||
async setup() {
|
||||
const calendarPromise = loadCalendar();
|
||||
|
||||
return {
|
||||
selectedDay: storeToRefs(useMainStore()).selectedDay,
|
||||
calendar: await calendarPromise,
|
||||
};
|
||||
},
|
||||
data(): Data {
|
||||
return {
|
||||
svg: logoSvg.replace('/></svg>', 'fill="currentColor"/></svg>'),
|
||||
flagName: null,
|
||||
forceShowFlagDyn: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
selectedDay() {
|
||||
this.forceShowFlagDyn = !!this.selectedDay;
|
||||
// removing the flag from the selected day is deferred until the transition has finished
|
||||
// so that it does not suddenly change
|
||||
if (this.selectedDay !== null) {
|
||||
this.flagName = this.selectFlag();
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
selectFlag(): string | null {
|
||||
const events = this.calendar.getCurrentYear()!.eventsByDate[(this.selectedDay || this.day).toString()];
|
||||
if (!events) {
|
||||
return null;
|
||||
}
|
||||
return new ImmutableArray(...events)
|
||||
.filter((e) => e.display.type === 'flag' && !e.display.name.startsWith('_'))
|
||||
.sorted((a, b) => b.level - a.level)
|
||||
.groupBy((e) => e.level)
|
||||
.indexOrFallback(0, ['0', new ImmutableArray()])[1]
|
||||
.map((e) => e.display.name)
|
||||
.randomElement();
|
||||
},
|
||||
resetFlagIfNotOverwritten(): void {
|
||||
if (this.selectedDay === null) {
|
||||
this.flagName = this.selectFlag();
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.logo-wrapper {
|
||||
width: 1.3em;
|
||||
|
Loading…
x
Reference in New Issue
Block a user