Migrate to Vue 3 and Vite
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -1,111 +1,117 @@
|
||||
<template>
|
||||
<div v-if="config">
|
||||
<section class="hero is-primary">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h1 class="title" dir="auto">{{ config.name }}</h1>
|
||||
<p dir="auto">{{ config.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<section class="p-6 bg-primary text-white">
|
||||
<h1 dir="auto">{{ config.name }}</h1>
|
||||
<p dir="auto">{{ config.description }}</p>
|
||||
</section>
|
||||
<section class="columns contact-statistics" v-if="statistics">
|
||||
<div class="column is-three-quarters-desktop statistics">
|
||||
<i18n tag="p" path="Home to {number} users">
|
||||
<strong slot="number">{{ statistics.numberOfUsers }}</strong>
|
||||
</i18n>
|
||||
<i18n tag="p" path="and {number} groups">
|
||||
<strong slot="number">{{ statistics.numberOfLocalGroups }}</strong>
|
||||
</i18n>
|
||||
<i18n tag="p" path="Who published {number} events">
|
||||
<strong slot="number">{{ statistics.numberOfLocalEvents }}</strong>
|
||||
</i18n>
|
||||
<i18n tag="p" path="And {number} comments">
|
||||
<strong slot="number">{{ statistics.numberOfLocalComments }}</strong>
|
||||
</i18n>
|
||||
<section
|
||||
class="px-2 flex flex-wrap gap-2 contact-statistics"
|
||||
v-if="statistics"
|
||||
>
|
||||
<div class="statistics flex-1 min-w-[20rem]">
|
||||
<i18n-t tag="p" keypath="Home to {number} users">
|
||||
<template v-slot:number>
|
||||
<strong>{{ statistics.numberOfUsers }}</strong>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<i18n-t tag="p" keypath="and {number} groups">
|
||||
<template v-slot:number>
|
||||
<strong>{{ statistics.numberOfLocalGroups }}</strong>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<i18n-t tag="p" keypath="Who published {number} events">
|
||||
<template v-slot:number>
|
||||
<strong>{{ statistics.numberOfLocalEvents }}</strong>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<i18n-t tag="p" keypath="And {number} comments">
|
||||
<template v-slot:number>
|
||||
<strong>{{ statistics.numberOfLocalComments }}</strong>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</div>
|
||||
<div class="column contact">
|
||||
<p class="has-text-weight-bold">{{ $t("Contact") }}</p>
|
||||
<div class="">
|
||||
<p class="font-bold">{{ t("Contact") }}</p>
|
||||
<instance-contact-link
|
||||
v-if="config && config.contact"
|
||||
:contact="config.contact"
|
||||
/>
|
||||
<p v-else>{{ $t("No information") }}</p>
|
||||
<p v-else>{{ t("No information") }}</p>
|
||||
</div>
|
||||
</section>
|
||||
<hr role="presentation" />
|
||||
<hr role="presentation" v-if="config.longDescription" />
|
||||
<section class="long-description content">
|
||||
<div v-html="config.longDescription" />
|
||||
</section>
|
||||
<hr role="presentation" />
|
||||
<section class="config">
|
||||
<h2 class="subtitle">{{ $t("Instance configuration") }}</h2>
|
||||
<table class="table is-fullwidth">
|
||||
<tr>
|
||||
<td>{{ $t("Instance languages") }}</td>
|
||||
<section class="px-3">
|
||||
<h2 class="text-xl">{{ t("Instance configuration") }}</h2>
|
||||
<table class="border-collapse table-auto w-full">
|
||||
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
|
||||
<td>{{ t("Instance languages") }}</td>
|
||||
<td
|
||||
v-if="config.languages.length > 0"
|
||||
:title="this.config ? this.config.languages.join(', ') : ''"
|
||||
:title="config.languages.join(', ') ?? ''"
|
||||
>
|
||||
{{ formattedLanguageList }}
|
||||
</td>
|
||||
<td v-else>{{ $t("No information") }}</td>
|
||||
<td v-else>{{ t("No information") }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("Mobilizon version") }}</td>
|
||||
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
|
||||
<td>{{ t("Mobilizon version") }}</td>
|
||||
<td>{{ config.version }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("Registrations") }}</td>
|
||||
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
|
||||
<td>{{ t("Registrations") }}</td>
|
||||
<td v-if="config.registrationsOpen && config.registrationsAllowlist">
|
||||
{{ $t("Restricted") }}
|
||||
{{ t("Restricted") }}
|
||||
</td>
|
||||
<td v-if="config.registrationsOpen && !config.registrationsAllowlist">
|
||||
{{ $t("Open") }}
|
||||
{{ t("Open") }}
|
||||
</td>
|
||||
<td v-else>{{ $t("Closed") }}</td>
|
||||
<td v-else>{{ t("Closed") }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("Federation") }}</td>
|
||||
<td v-if="config.federating">{{ $t("Enabled") }}</td>
|
||||
<td v-else>{{ $t("Disabled") }}</td>
|
||||
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
|
||||
<td>{{ t("Federation") }}</td>
|
||||
<td v-if="config.federating">{{ t("Enabled") }}</td>
|
||||
<td v-else>{{ t("Disabled") }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ $t("Anonymous participations") }}</td>
|
||||
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
|
||||
<td>{{ t("Anonymous participations") }}</td>
|
||||
<td v-if="config.anonymous.participation.allowed">
|
||||
{{ $t("If allowed by organizer") }}
|
||||
{{ t("If allowed by organizer") }}
|
||||
</td>
|
||||
<td v-else>{{ $t("Disabled") }}</td>
|
||||
<td v-else>{{ t("Disabled") }}</td>
|
||||
</tr>
|
||||
<tr class="instance-feeds">
|
||||
<td>{{ $t("Instance feeds") }}</td>
|
||||
<td v-if="config.instanceFeeds.enabled" class="buttons">
|
||||
<b-button
|
||||
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
|
||||
<td>{{ t("Instance feeds") }}</td>
|
||||
<td v-if="config.instanceFeeds.enabled" class="flex gap-2">
|
||||
<o-button
|
||||
tag="a"
|
||||
size="is-small"
|
||||
size="small"
|
||||
icon-left="rss"
|
||||
href="/feed/instance/atom"
|
||||
target="_blank"
|
||||
>{{ $t("RSS/Atom Feed") }}</b-button
|
||||
>{{ t("RSS/Atom Feed") }}</o-button
|
||||
>
|
||||
|
||||
<b-button
|
||||
<o-button
|
||||
tag="a"
|
||||
size="is-small"
|
||||
size="small"
|
||||
icon-left="calendar-sync"
|
||||
href="/feed/instance/ics"
|
||||
target="_blank"
|
||||
>{{ $t("ICS/WebCal Feed") }}</b-button
|
||||
>{{ t("ICS/WebCal Feed") }}</o-button
|
||||
>
|
||||
</td>
|
||||
<td v-else>{{ $t("Disabled") }}</td>
|
||||
<td v-else>{{ t("Disabled") }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from "vue-property-decorator";
|
||||
<script lang="ts" setup>
|
||||
import { formatList } from "@/utils/i18n";
|
||||
import InstanceContactLink from "@/components/About/InstanceContactLink.vue";
|
||||
import { LANGUAGES_CODES } from "@/graphql/admin";
|
||||
@@ -114,51 +120,51 @@ import { ABOUT } from "../../graphql/config";
|
||||
import { STATISTICS } from "../../graphql/statistics";
|
||||
import { IConfig } from "../../types/config.model";
|
||||
import { IStatistics } from "../../types/statistics.model";
|
||||
import { useQuery } from "@vue/apollo-composable";
|
||||
import { computed } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
config: ABOUT,
|
||||
statistics: STATISTICS,
|
||||
languages: {
|
||||
query: LANGUAGES_CODES,
|
||||
variables() {
|
||||
return {
|
||||
codes: this?.config.languages,
|
||||
};
|
||||
},
|
||||
skip() {
|
||||
return !this.config || !this.config?.languages;
|
||||
},
|
||||
},
|
||||
},
|
||||
components: {
|
||||
InstanceContactLink,
|
||||
},
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.$t("About {instance}", {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
instance: this?.config?.name,
|
||||
}) as string,
|
||||
};
|
||||
},
|
||||
})
|
||||
export default class AboutInstance extends Vue {
|
||||
config!: IConfig;
|
||||
const { result: configResult } = useQuery<{ config: IConfig }>(ABOUT);
|
||||
|
||||
statistics!: IStatistics;
|
||||
const config = computed(() => configResult.value?.config);
|
||||
|
||||
languages!: ILanguage[];
|
||||
const { result: statisticsResult } = useQuery<{ statistics: IStatistics }>(
|
||||
STATISTICS
|
||||
);
|
||||
|
||||
get formattedLanguageList(): string {
|
||||
if (this.languages) {
|
||||
const list = this.languages.map(({ name }) => name);
|
||||
return formatList(list);
|
||||
}
|
||||
return "";
|
||||
const statistics = computed(() => statisticsResult.value?.statistics);
|
||||
|
||||
const { result: languagesResult } = useQuery<{ languages: ILanguage[] }>(
|
||||
LANGUAGES_CODES,
|
||||
() => ({
|
||||
codes: config.value?.languages,
|
||||
}),
|
||||
() => ({
|
||||
enabled: config.value?.languages !== undefined,
|
||||
})
|
||||
);
|
||||
|
||||
const languages = computed(() => languagesResult.value?.languages);
|
||||
|
||||
const formattedLanguageList = computed((): string => {
|
||||
if (languages.value) {
|
||||
const list = languages.value?.map(({ name }) => name) ?? [];
|
||||
return formatList(list);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
});
|
||||
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
|
||||
// metaInfo() {
|
||||
// return {
|
||||
// title: this.t("About {instance}", {
|
||||
// // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// // @ts-ignore
|
||||
// instance: this?.config?.name,
|
||||
// }) as string,
|
||||
// };
|
||||
// }
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -194,17 +200,6 @@ section {
|
||||
}
|
||||
}
|
||||
}
|
||||
.contact {
|
||||
h3 {
|
||||
font-weight: bold;
|
||||
}
|
||||
p {
|
||||
width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
tr.instance-feeds {
|
||||
height: 3rem;
|
||||
|
||||
@@ -1,60 +1,65 @@
|
||||
<template>
|
||||
<div class="container section">
|
||||
<h2 class="title">{{ $t("Glossary") }}</h2>
|
||||
<div class="content" v-if="config">
|
||||
<div class="container mx-auto px-2">
|
||||
<h1>{{ t("Glossary") }}</h1>
|
||||
<div class="prose dark:prose-invert" v-if="config">
|
||||
<p>
|
||||
{{
|
||||
$t(
|
||||
t(
|
||||
"Some terms, technical or otherwise, used in the text below may cover concepts that are difficult to grasp. We have provided a glossary here to help you understand them better:"
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<dl>
|
||||
<dt>{{ $t("Instance") }}</dt>
|
||||
<i18n
|
||||
<dt>{{ t("Instance") }}</dt>
|
||||
<i18n-t
|
||||
tag="dd"
|
||||
path="An instance is an installed version of the Mobilizon software running on a server. An instance can be run by anyone using the {mobilizon_software} or other federated apps, aka the “fediverse”. This instance's name is {instance_name}. Mobilizon is a federated network of multiple instances (just like email servers), users registered on different instances may communicate even though they didn't register on the same instance."
|
||||
keypath="An instance is an installed version of the Mobilizon software running on a server. An instance can be run by anyone using the {mobilizon_software} or other federated apps, aka the “fediverse”. This instance's name is {instance_name}. Mobilizon is a federated network of multiple instances (just like email servers), users registered on different instances may communicate even though they didn't register on the same instance."
|
||||
>
|
||||
<a slot="mobilizon_software" href="https://joinmobilizon.org">{{
|
||||
$t("Mobilizon software")
|
||||
}}</a>
|
||||
<b slot="instance_name">{{ config.name }}</b>
|
||||
</i18n>
|
||||
<dt>{{ $t("Instance administrator") }}</dt>
|
||||
<template #mobilizon_software
|
||||
><a href="https://joinmobilizon.org">{{
|
||||
t("Mobilizon software")
|
||||
}}</a></template
|
||||
>
|
||||
|
||||
<template #instance_name>
|
||||
<b>{{ config.name }}</b>
|
||||
</template>
|
||||
</i18n-t>
|
||||
<dt>{{ t("Instance administrator") }}</dt>
|
||||
<dd>
|
||||
{{
|
||||
$t(
|
||||
t(
|
||||
"The instance administrator is the person or entity that runs this Mobilizon instance."
|
||||
)
|
||||
}}
|
||||
</dd>
|
||||
<dt>{{ $t("Application") }}</dt>
|
||||
<dt>{{ t("Application") }}</dt>
|
||||
<dd>
|
||||
{{
|
||||
$t(
|
||||
t(
|
||||
"In the following context, an application is a software, either provided by the Mobilizon team or by a 3rd-party, used to interact with your instance."
|
||||
)
|
||||
}}
|
||||
</dd>
|
||||
<dt>{{ $t("API") }}</dt>
|
||||
<dt>{{ t("API") }}</dt>
|
||||
<dd>
|
||||
{{
|
||||
$t(
|
||||
t(
|
||||
"An “application programming interface” or “API” is a communication protocol that allows software components to communicate with each other. The Mobilizon API, for example, can allow third-party software tools to communicate with Mobilizon instances to carry out certain actions, such as posting events on your behalf, automatically and remotely."
|
||||
)
|
||||
}}
|
||||
</dd>
|
||||
<dt>{{ $t("SSL/TLS") }}</dt>
|
||||
<i18n
|
||||
<dt>{{ t("SSL/TLS") }}</dt>
|
||||
<i18n-t
|
||||
tag="dd"
|
||||
path="SSL and it's successor TLS are encryption technologies to secure data communications when using the service. You can recognize an encrypted connection in your browser's address line when the URL begins with {https} and the lock icon is displayed in your browser's address bar."
|
||||
keypath="SSL and it's successor TLS are encryption technologies to secure data communications when using the service. You can recognize an encrypted connection in your browser's address line when the URL begins with {https} and the lock icon is displayed in your browser's address bar."
|
||||
>
|
||||
<code slot="https">https://</code>
|
||||
</i18n>
|
||||
<dt>{{ $t("Cookies and Local storage") }}</dt>
|
||||
<template v-slot:https><code>https://</code></template>
|
||||
</i18n-t>
|
||||
<dt>{{ t("Cookies and Local storage") }}</dt>
|
||||
<dd>
|
||||
{{
|
||||
$t(
|
||||
t(
|
||||
"A cookie is a small file containing information that is sent to your computer when you visit a website. When you visit the site again, the cookie allows that site to recognize your browser. Cookies may store user preferences and other information. You can configure your browser to refuse all cookies. However, this may result in some website features or services partially working. Local storage works the same way but allows you to store more data."
|
||||
)
|
||||
}}
|
||||
@@ -64,28 +69,28 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from "vue-property-decorator";
|
||||
<script lang="ts" setup>
|
||||
import { useQuery } from "@vue/apollo-composable";
|
||||
import { computed } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { ABOUT } from "../../graphql/config";
|
||||
import { IConfig } from "../../types/config.model";
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
config: ABOUT,
|
||||
},
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.$t("Glossary") as string,
|
||||
};
|
||||
},
|
||||
})
|
||||
export default class Glossary extends Vue {
|
||||
config!: IConfig;
|
||||
}
|
||||
const { result: configResult } = useQuery<{ config: IConfig }>(ABOUT);
|
||||
|
||||
const config = computed(() => configResult.value?.config);
|
||||
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
|
||||
// metaInfo() {
|
||||
// return {
|
||||
// title: this.t("Glossary") as string,
|
||||
// };
|
||||
// },
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
::v-deep dt {
|
||||
:deep(dt) {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,72 +1,47 @@
|
||||
<template>
|
||||
<div class="container section">
|
||||
<h2 class="title">{{ $t("Privacy Policy") }}</h2>
|
||||
<div class="container mx-auto px-2">
|
||||
<h1>{{ t("Privacy Policy") }}</h1>
|
||||
<div
|
||||
class="content"
|
||||
v-if="config && config.privacy"
|
||||
class="prose dark:prose-invert"
|
||||
v-if="config?.privacy"
|
||||
v-html="config.privacy.bodyHtml"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Watch } from "vue-property-decorator";
|
||||
<script lang="ts" setup>
|
||||
import { PRIVACY } from "@/graphql/config";
|
||||
import { IConfig } from "@/types/config.model";
|
||||
import { InstancePrivacyType } from "@/types/enums";
|
||||
import { useQuery } from "@vue/apollo-composable";
|
||||
import { computed, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
config: {
|
||||
query: PRIVACY,
|
||||
variables() {
|
||||
return {
|
||||
locale: this.locale,
|
||||
};
|
||||
},
|
||||
skip() {
|
||||
return !this.locale;
|
||||
},
|
||||
},
|
||||
},
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.$t("Privacy Policy") as string,
|
||||
};
|
||||
},
|
||||
})
|
||||
export default class Privacy extends Vue {
|
||||
config!: IConfig;
|
||||
const { locale } = useI18n({ useScope: "global" });
|
||||
|
||||
locale: string | null = null;
|
||||
const { result: configResult } = useQuery<{ config: IConfig }>(
|
||||
PRIVACY,
|
||||
() => ({
|
||||
locale: locale.value,
|
||||
}),
|
||||
() => ({
|
||||
enabled: locale.value !== undefined,
|
||||
})
|
||||
);
|
||||
|
||||
created(): void {
|
||||
this.locale = this.$i18n.locale;
|
||||
const config = computed(() => configResult.value?.config);
|
||||
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
|
||||
// metaInfo() {
|
||||
// return {
|
||||
// title: this.t("Privacy Policy") as string,
|
||||
// };
|
||||
// },
|
||||
|
||||
watch(config, () => {
|
||||
if (config.value?.privacy?.type === InstancePrivacyType.URL) {
|
||||
window.location.replace(config.value?.privacy?.url);
|
||||
}
|
||||
|
||||
@Watch("config", { deep: true })
|
||||
watchConfig(config: IConfig): void {
|
||||
if (config?.privacy?.type) {
|
||||
this.redirectToUrl();
|
||||
}
|
||||
}
|
||||
|
||||
redirectToUrl(): void {
|
||||
if (this.config?.privacy?.type === InstancePrivacyType.URL) {
|
||||
window.location.replace(this.config?.privacy?.url);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
main > .container {
|
||||
background: $white;
|
||||
|
||||
::v-deep dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.content ::v-deep li {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,40 +1,31 @@
|
||||
<template>
|
||||
<div class="container section" v-if="config">
|
||||
<h2 class="title">{{ $t("Rules") }}</h2>
|
||||
<div class="content" v-html="config.rules" v-if="config.rules" />
|
||||
<p v-else>{{ $t("No rules defined yet.") }}</p>
|
||||
<div class="container mx-auto px-2" v-if="config">
|
||||
<h1>{{ t("Rules") }}</h1>
|
||||
<div
|
||||
class="prose dark:prose-invert"
|
||||
v-html="config.rules"
|
||||
v-if="config.rules"
|
||||
/>
|
||||
<p v-else>{{ t("No rules defined yet.") }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from "vue-property-decorator";
|
||||
<script lang="ts" setup>
|
||||
import { RULES } from "@/graphql/config";
|
||||
import { IConfig } from "@/types/config.model";
|
||||
import RouteName from "../../router/name";
|
||||
import { useQuery } from "@vue/apollo-composable";
|
||||
import { computed } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
config: {
|
||||
query: RULES,
|
||||
},
|
||||
},
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.$t("Rules") as string,
|
||||
};
|
||||
},
|
||||
})
|
||||
export default class Rules extends Vue {
|
||||
config!: IConfig;
|
||||
const { result: configResult } = useQuery<{ config: IConfig }>(RULES);
|
||||
|
||||
RouteName = RouteName;
|
||||
}
|
||||
const config = computed(() => configResult.value?.config);
|
||||
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
|
||||
// metaInfo() {
|
||||
// return {
|
||||
// title: this.t("Rules") as string,
|
||||
// };
|
||||
// },
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
main > .container {
|
||||
background: $white;
|
||||
}
|
||||
.content ::v-deep li {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,61 +1,53 @@
|
||||
<template>
|
||||
<div class="container section">
|
||||
<h2 class="title">{{ $t("Terms") }}</h2>
|
||||
<div class="content" v-if="config" v-html="config.terms.bodyHtml" />
|
||||
<div class="container mx-auto px-2">
|
||||
<h1>{{ t("Terms") }}</h1>
|
||||
<o-loading v-model="termsLoading" />
|
||||
<div
|
||||
class="prose dark:prose-invert"
|
||||
v-if="config"
|
||||
v-html="config.terms.bodyHtml"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Watch } from "vue-property-decorator";
|
||||
<script lang="ts" setup>
|
||||
import { TERMS } from "@/graphql/config";
|
||||
import { IConfig } from "@/types/config.model";
|
||||
import { InstanceTermsType } from "@/types/enums";
|
||||
import { useQuery } from "@vue/apollo-composable";
|
||||
import { useHead } from "@vueuse/head";
|
||||
import { computed, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
config: {
|
||||
query: TERMS,
|
||||
variables() {
|
||||
return {
|
||||
locale: this.locale,
|
||||
};
|
||||
},
|
||||
skip() {
|
||||
return !this.locale;
|
||||
},
|
||||
},
|
||||
},
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.$t("Terms") as string,
|
||||
};
|
||||
},
|
||||
})
|
||||
export default class Terms extends Vue {
|
||||
config!: IConfig;
|
||||
const { t, locale } = useI18n({ useScope: "global" });
|
||||
|
||||
locale: string | null = null;
|
||||
const { result: termsResult, loading: termsLoading } = useQuery<{
|
||||
config: IConfig;
|
||||
}>(
|
||||
TERMS,
|
||||
() => ({
|
||||
locale: locale.value,
|
||||
}),
|
||||
() => ({
|
||||
enabled: locale.value !== undefined,
|
||||
})
|
||||
);
|
||||
|
||||
created(): void {
|
||||
this.locale = this.$i18n.locale;
|
||||
const config = computed(() => termsResult.value?.config);
|
||||
|
||||
watch(config, () => {
|
||||
if (config.value?.terms?.type) {
|
||||
redirectToUrl();
|
||||
}
|
||||
});
|
||||
|
||||
@Watch("config", { deep: true })
|
||||
watchConfig(config: IConfig): void {
|
||||
if (config?.terms?.type) {
|
||||
this.redirectToUrl();
|
||||
}
|
||||
const redirectToUrl = (): void => {
|
||||
if (config.value?.terms?.type === InstanceTermsType.URL) {
|
||||
window.location.replace(config.value?.terms?.url);
|
||||
}
|
||||
};
|
||||
|
||||
redirectToUrl(): void {
|
||||
if (this.config?.terms?.type === InstanceTermsType.URL) {
|
||||
window.location.replace(this.config?.terms?.url);
|
||||
}
|
||||
}
|
||||
}
|
||||
useHead({
|
||||
title: computed(() => t("Terms")),
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.content ::v-deep li {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user