Switch to translatable data
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { useI18nKey } from '~/composables/useI18nKey';
|
||||
import { useTitleStore } from '~/stores/title';
|
||||
|
||||
definePageMeta({
|
||||
@@ -9,6 +10,7 @@ const app = useNuxtApp();
|
||||
const { loggedIn } = useUserSession();
|
||||
const localePath = useLocalePath();
|
||||
const { t } = useI18n();
|
||||
const { tKey, hasKey, tSluggy } = useI18nKey();
|
||||
const router = useRouter();
|
||||
|
||||
const { huntSlug } = app.$slugData;
|
||||
@@ -21,7 +23,7 @@ const { data, pending, refresh, error } = await useFetch(
|
||||
|
||||
useHead({
|
||||
title: t('layouts.title', {
|
||||
title: data.value?.title || name
|
||||
title: hasKey(data.value, 'title') ? tKey(data.value!, 'title').value : name
|
||||
})
|
||||
});
|
||||
|
||||
@@ -31,8 +33,7 @@ watch(loggedIn, (isLoggedIn) => {
|
||||
}
|
||||
});
|
||||
|
||||
titleStore.title = data.value?.title;
|
||||
// TODO: handle data!
|
||||
titleStore.title = data.value ? tKey(data.value, 'title').value : undefined;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -40,7 +41,11 @@ titleStore.title = data.value?.title;
|
||||
<VaButtonGroup>
|
||||
<VaButton
|
||||
icon="arrow_back"
|
||||
:to="$localePath(`/hunt/${sluggy(data?.hunt || huntSlug!)}`)"
|
||||
:to="
|
||||
$localePath(
|
||||
`/hunt/${data ? tSluggy(data.hunt).value : sluggy(huntSlug!)}`
|
||||
)
|
||||
"
|
||||
>Back to Hunt</VaButton
|
||||
>
|
||||
<VaButton icon="replay" color="success" @click="refresh">Refresh</VaButton>
|
||||
@@ -54,7 +59,7 @@ titleStore.title = data.value?.title;
|
||||
<div v-if="data">
|
||||
<p>{{ data.points }} Points</p>
|
||||
<p v-if="data.extraPoints">{{ data.extraPoints }} Extra points</p>
|
||||
<p v-if="data.extraText">Extra: {{ data.extraText }}</p>
|
||||
<p v-if="hasKey(data, 'extraText')">Extra: {{ tKey(data, 'extraText') }}</p>
|
||||
</div>
|
||||
<div v-if="data && data.answers.length > 0">
|
||||
<VaAccordion multiple stateful>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import ClickableImage from '~/components/ClickableImage.vue';
|
||||
import { useI18nKey } from '~/composables/useI18nKey';
|
||||
import { useTitleStore } from '~/stores/title';
|
||||
import { fullDate } from '~~/server/utils/date';
|
||||
|
||||
@@ -12,7 +13,8 @@ const app = useNuxtApp();
|
||||
const { user } = useUserSession();
|
||||
const { huntSlug, questSlug } = app.$slugData;
|
||||
|
||||
const { t, d } = useI18n();
|
||||
const { t, d, locale } = useI18n();
|
||||
const { tKey, hasKey, tSluggy } = useI18nKey();
|
||||
|
||||
const titleStore = useTitleStore();
|
||||
|
||||
@@ -20,13 +22,18 @@ const { data, pending, refresh, error } = await useFetch(
|
||||
`/api/quest/${questSlug?.id}`
|
||||
);
|
||||
|
||||
titleStore.title = data.value?.title;
|
||||
titleStore.title = data.value ? tKey(data.value, 'title').value : undefined;
|
||||
|
||||
useHead({
|
||||
title: t('layouts.title', {
|
||||
title:
|
||||
[
|
||||
data.value?.title || questSlug?.name,
|
||||
data.value?.hunt?.name || huntSlug?.name
|
||||
hasKey(data.value, 'title')
|
||||
? tKey(data.value, 'title').value
|
||||
: questSlug?.name,
|
||||
hasKey(data.value?.hunt, 'name')
|
||||
? tKey(data.value?.hunt, 'name').value
|
||||
: huntSlug?.name
|
||||
]
|
||||
.filter((s) => s && s?.length > 0)
|
||||
.join(' | ') || t('layouts.default_tile')
|
||||
@@ -52,6 +59,7 @@ async function submit() {
|
||||
submitError.value = '';
|
||||
|
||||
const body = new FormData();
|
||||
body.set('lang', locale.value);
|
||||
|
||||
if (data.value?.answer?.updatedAt) {
|
||||
body.set('updatedAt', data.value?.answer?.updatedAt);
|
||||
@@ -100,7 +108,11 @@ const createImageURL = (file: File) => URL.createObjectURL(file);
|
||||
<VaButtonGroup>
|
||||
<VaButton
|
||||
icon="arrow_back"
|
||||
:to="$localePath(`/hunt/${sluggy(data?.hunt || huntSlug!)}`)"
|
||||
:to="
|
||||
$localePath(
|
||||
`/hunt/${data ? tSluggy(data.hunt).value : sluggy(huntSlug!)}`
|
||||
)
|
||||
"
|
||||
>Back to Hunt</VaButton
|
||||
>
|
||||
<VaButton
|
||||
@@ -118,7 +130,7 @@ const createImageURL = (file: File) => URL.createObjectURL(file);
|
||||
color="danger"
|
||||
:to="
|
||||
$localePath(
|
||||
`/hunt/${sluggy(data?.hunt || huntSlug!)}/${sluggy(data || questSlug)}/admin`
|
||||
`/hunt/${data?.hunt ? tSluggy(data.hunt).value : sluggy(huntSlug!)}/${data ? tSluggy(data).value : sluggy(questSlug!)}}/admin`
|
||||
)
|
||||
"
|
||||
>Admin</VaButton
|
||||
@@ -138,19 +150,21 @@ const createImageURL = (file: File) => URL.createObjectURL(file);
|
||||
<ClickableImage
|
||||
v-if="data?.picture"
|
||||
:src="data?.picture?.url"
|
||||
:title="data?.title || questSlug?.name || ''"
|
||||
:title="(data ? tKey(data, 'title').value : questSlug?.name) || ''"
|
||||
/>
|
||||
<VaCardContent>
|
||||
<div class="flex flex-col gap-4">
|
||||
<p class="text-lg">{{ data.description }}</p>
|
||||
<p v-if="data.question" class="text-xl font-bold">
|
||||
{{ data.textRequired ? '❓' : '❔' }}: {{ data.question }}
|
||||
<p class="text-lg">{{ tKey(data, 'description') }}</p>
|
||||
<p v-if="hasKey(data, 'question')" class="text-xl font-bold">
|
||||
{{ data.textRequired ? '❓' : '❔' }}:
|
||||
{{ tKey(data, 'question') }}
|
||||
</p>
|
||||
<p v-if="data.question">
|
||||
<p v-if="hasKey(data, 'question')">
|
||||
🖋: {{ t(`enums.text_type.${data.textType}`) }}
|
||||
</p>
|
||||
<p v-if="data.extraText">
|
||||
<span class="uppercase">Extra points:</span> {{ data.extraText }}
|
||||
<p v-if="hasKey(data, 'extraText')">
|
||||
<span class="uppercase">Extra points:</span>
|
||||
{{ tKey(data, 'extraText') }}
|
||||
</p>
|
||||
</div>
|
||||
</VaCardContent>
|
||||
@@ -166,7 +180,10 @@ const createImageURL = (file: File) => URL.createObjectURL(file);
|
||||
{{ d(data.answer.review.updatedAt, fullDate) }}</span
|
||||
>
|
||||
</p>
|
||||
<div class="flex max-h-[60dvh] flex-col gap-2 overflow-y-auto pr-4">
|
||||
<div
|
||||
class="flex max-h-[60dvh] flex-col gap-2 overflow-y-auto pr-4"
|
||||
v-if="data.answer.review.review"
|
||||
>
|
||||
<p
|
||||
v-for="(line, i) in data.answer.review.review.split('\n')"
|
||||
:key="i"
|
||||
@@ -186,9 +203,9 @@ const createImageURL = (file: File) => URL.createObjectURL(file);
|
||||
<VaCardContent>
|
||||
<div class="flex flex-col gap-4">
|
||||
<VaInput
|
||||
:label="data.question"
|
||||
:label="tKey(data, 'question').value"
|
||||
:disabled="uploading || data.answer?.final"
|
||||
v-if="data.question"
|
||||
v-if="hasKey(data, 'question')"
|
||||
placeholder="Your answer"
|
||||
:required-mark="data.textRequired"
|
||||
v-model="answer"
|
||||
@@ -198,7 +215,7 @@ const createImageURL = (file: File) => URL.createObjectURL(file);
|
||||
:type="textType[data.textType]"
|
||||
:messages="[
|
||||
t(`enums.text_type.${data.textType}`),
|
||||
data.textRequired ? 'Required Answer' : undefined
|
||||
data.textRequired ? 'Required Answer' : ''
|
||||
]"
|
||||
>
|
||||
<template v-if="data.textUnit" #appendInner>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import superjson, { type SuperJSONResult } from 'superjson';
|
||||
import { useI18nKey } from '~/composables/useI18nKey';
|
||||
import { useTitleStore } from '~/stores/title';
|
||||
import { fullDate } from '~~/server/utils/date';
|
||||
|
||||
@@ -11,6 +12,7 @@ const app = useNuxtApp();
|
||||
const { loggedIn } = useUserSession();
|
||||
const localePath = useLocalePath();
|
||||
const { t, d } = useI18n();
|
||||
const { tKey, hasKey } = useI18nKey();
|
||||
const router = useRouter();
|
||||
|
||||
const { confirm } = useModal();
|
||||
@@ -36,7 +38,7 @@ const formData = useCloned(data, {
|
||||
|
||||
useHead({
|
||||
title: t('layouts.title', {
|
||||
title: data.value?.name || name
|
||||
title: hasKey(data.value, 'name') ? tKey(data.value!, 'name').value : name
|
||||
})
|
||||
});
|
||||
|
||||
@@ -46,7 +48,7 @@ watch(loggedIn, (isLoggedIn) => {
|
||||
}
|
||||
});
|
||||
|
||||
titleStore.title = data.value?.name;
|
||||
titleStore.title = data.value ? tKey(data.value, 'name').value : undefined;
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
@@ -114,6 +116,7 @@ async function kick(member: {
|
||||
init({
|
||||
title: 'Error while kicking',
|
||||
color: 'danger',
|
||||
// @ts-expect-error weird error stuff
|
||||
message: e?.message || e?.statusMessage || t(parseError(e))
|
||||
});
|
||||
}
|
||||
@@ -143,6 +146,7 @@ async function addUser() {
|
||||
init({
|
||||
title: 'Error while adding',
|
||||
color: 'danger',
|
||||
// @ts-expect-error weird error stuff
|
||||
message: e?.message || e?.statusMessage || t(parseError(e))
|
||||
});
|
||||
}
|
||||
@@ -157,17 +161,31 @@ async function addUser() {
|
||||
<h1>admin</h1>
|
||||
<VaForm v-if="formData.cloned.value && data" class="flex flex-col gap-4">
|
||||
<VaInput
|
||||
label="Name"
|
||||
v-model="formData.cloned.value.name"
|
||||
label="Name DE"
|
||||
v-model="formData.cloned.value.name_de"
|
||||
clearable
|
||||
:clear-value="data.name"
|
||||
:clear-value="data.name_de"
|
||||
clearable-icon="replay"
|
||||
/>
|
||||
<VaInput
|
||||
label="Name EN"
|
||||
v-model="formData.cloned.value.name_en"
|
||||
clearable
|
||||
:clear-value="data.name_en"
|
||||
clearable-icon="replay"
|
||||
/>
|
||||
<VaTextarea
|
||||
label="Description"
|
||||
v-model="formData.cloned.value.description"
|
||||
label="Description DE"
|
||||
v-model="formData.cloned.value.description_de"
|
||||
clearable
|
||||
:clear-value="data.description"
|
||||
:clear-value="data.description_de"
|
||||
clearable-icon="replay"
|
||||
/>
|
||||
<VaTextarea
|
||||
label="Description EN"
|
||||
v-model="formData.cloned.value.description_en"
|
||||
clearable
|
||||
:clear-value="data.description_en"
|
||||
clearable-icon="replay"
|
||||
/>
|
||||
<VaCheckbox label="Virtual" v-model="formData.cloned.value.virtual" />
|
||||
|
||||
@@ -7,13 +7,14 @@ definePageMeta({
|
||||
const app = useNuxtApp();
|
||||
const { loggedIn } = useUserSession();
|
||||
const { t } = useI18n();
|
||||
const { tKey } = useI18nKey();
|
||||
|
||||
const { name, id } = app.$slugData.huntSlug!;
|
||||
|
||||
const titleStore = useTitleStore();
|
||||
|
||||
type Picture = {
|
||||
quest: { id: number; title: string };
|
||||
quest: { id: number; title_de: string; title_en: string };
|
||||
team: {
|
||||
name: string;
|
||||
id: number;
|
||||
@@ -81,7 +82,7 @@ titleStore.title = data.value?.name;
|
||||
<p
|
||||
class="absolute top-2 mx-auto rounded bg-gray-200/75 px-2 py-1 text-center text-xl font-bold"
|
||||
>
|
||||
{{ item.quest.title }} — {{ item.team.name }} —
|
||||
{{ tKey(item.quest, 'title') }} — {{ item.team.name }} —
|
||||
{{ item.picture.creator.name }}
|
||||
</p></template
|
||||
></VaCarousel
|
||||
|
||||
@@ -5,8 +5,8 @@ import { fullDate } from '~~/server/utils/date';
|
||||
|
||||
const app = useNuxtApp();
|
||||
const { loggedIn } = useUserSession();
|
||||
const localePath = useLocalePath();
|
||||
const { t, d } = useI18n();
|
||||
const { tKey, hasKey, tSluggy } = useI18nKey();
|
||||
|
||||
const { name, id } = app.$slugData.huntSlug!;
|
||||
|
||||
@@ -18,13 +18,13 @@ const hideAnswers = ref(true);
|
||||
|
||||
useHead({
|
||||
title: t('layouts.title', {
|
||||
title: data.value?.name || name
|
||||
title: hasKey(data.value, 'name') ? tKey(data.value!, 'name').value : name
|
||||
})
|
||||
});
|
||||
|
||||
watch(loggedIn, () => refresh());
|
||||
|
||||
titleStore.title = data.value?.name;
|
||||
titleStore.title = data.value ? tKey(data.value, 'name').value : undefined;
|
||||
|
||||
async function invite() {
|
||||
if (!data.value?.ownTeam) {
|
||||
@@ -34,7 +34,7 @@ async function invite() {
|
||||
const clipboardItemData = {
|
||||
// TODO: add invite link
|
||||
// 'text/plain': `https://pichunt.syma.dev/hunt/${id}/join?id=${data.value.ownTeam.id}&pw=${data.value.ownTeam.password}`
|
||||
'text/plain': `Join team ${data.value.ownTeam.name} with code "${data.value.ownTeam.password}" on hunt "${data.value.name || name}"!`
|
||||
'text/plain': `Join team ${data.value.ownTeam.name} with code "${data.value.ownTeam.password}" on hunt "${data.value ? tKey(data.value, 'name').value : name}"!`
|
||||
};
|
||||
const clipboardItem = new ClipboardItem(clipboardItemData);
|
||||
await navigator.clipboard.write([clipboardItem]);
|
||||
@@ -43,7 +43,7 @@ async function invite() {
|
||||
|
||||
<template>
|
||||
<h1 class="text-2xl">
|
||||
{{ data?.name || name }}
|
||||
{{ data ? tKey(data, 'name') : name }}
|
||||
|
||||
<VaChip v-if="data?.totalScore" class="float-right" color="success"
|
||||
>Total points: {{ data!!.totalScore }}</VaChip
|
||||
@@ -58,40 +58,43 @@ async function invite() {
|
||||
v-if="(data?.revealAnswers && data?.revealQuests) || data?.isMember"
|
||||
color="success"
|
||||
icon="leaderboard"
|
||||
:to="$localePath(`/hunt/${sluggy(data)}/showcase`)"
|
||||
:to="$localePath(`/hunt/${tSluggy(data).value}/showcase`)"
|
||||
>Showcase</VaButton
|
||||
>
|
||||
<VaButton
|
||||
v-if="(data?.revealAnswers && data?.revealQuests) || data?.isMember"
|
||||
color="success"
|
||||
icon="collections"
|
||||
:to="$localePath(`/hunt/${sluggy(data)}/diashow`)"
|
||||
:to="$localePath(`/hunt/${tSluggy(data).value}/diashow`)"
|
||||
>Diashow</VaButton
|
||||
>
|
||||
<VaButton
|
||||
v-if="(data?.revealAnswers && data?.revealQuests) || data?.isMember"
|
||||
color="success"
|
||||
icon="auto_awesome_mosaic"
|
||||
:to="$localePath(`/hunt/${sluggy(data)}/pictures`)"
|
||||
:to="$localePath(`/hunt/${tSluggy(data).value}/pictures`)"
|
||||
>All pictures</VaButton
|
||||
>
|
||||
<VaButton
|
||||
v-if="data?.isMember"
|
||||
color="danger"
|
||||
icon="edit"
|
||||
:to="$localePath(`/hunt/${sluggy(data)}/admin`)"
|
||||
:to="$localePath(`/hunt/${tSluggy(data).value}/admin`)"
|
||||
>Admin</VaButton
|
||||
><VaButton
|
||||
v-if="data?.isMember"
|
||||
color="danger"
|
||||
icon="groups"
|
||||
:to="$localePath(`/hunt/${sluggy(data)}/teams`)"
|
||||
:to="$localePath(`/hunt/${tSluggy(data).value}/teams`)"
|
||||
>Teams</VaButton
|
||||
>
|
||||
</div>
|
||||
<div v-if="data">
|
||||
<div class="flex flex-col gap-2">
|
||||
<p v-for="(line, i) in data.description.split('\n')" :key="i">
|
||||
<p
|
||||
v-for="(line, i) in tKey(data, 'description').value.split('\n')"
|
||||
:key="i"
|
||||
>
|
||||
{{ line }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -99,7 +102,7 @@ async function invite() {
|
||||
v-if="data?.picture"
|
||||
:src="data?.picture?.url"
|
||||
class="h-48"
|
||||
:title="data?.name || name"
|
||||
:title="data ? tKey(data, 'name').value : name"
|
||||
/>
|
||||
<p v-if="data.start">
|
||||
Start:
|
||||
@@ -142,7 +145,7 @@ async function invite() {
|
||||
<VaButton
|
||||
color="info"
|
||||
icon="login"
|
||||
:to="$localePath(`/login?to=/hunt/${sluggy(data)}`)"
|
||||
:to="$localePath(`/login?to=/hunt/${tSluggy(data).value}`)"
|
||||
>Login first</VaButton
|
||||
>
|
||||
</VaCardActions>
|
||||
@@ -180,7 +183,7 @@ async function invite() {
|
||||
<template #loader> <VaProgressCircle indeterminate /> </template
|
||||
></VaImage>
|
||||
<VaCardContent>
|
||||
<p class="line-clamp-2 h-12">{{ quest.description }}</p>
|
||||
<p class="line-clamp-2 h-12">{{ tKey(quest, 'description') }}</p>
|
||||
|
||||
<div v-if="!hideAnswers && quest.answer?.text">
|
||||
<VaDivider />
|
||||
@@ -189,7 +192,11 @@ async function invite() {
|
||||
</VaCardContent>
|
||||
<VaCardActions>
|
||||
<VaButton
|
||||
:to="$localePath(`/hunt/${sluggy(data)}/${sluggy(quest)}`)"
|
||||
:to="
|
||||
$localePath(
|
||||
`/hunt/${tSluggy(data).value}/${tSluggy(quest).value}`
|
||||
)
|
||||
"
|
||||
color="primary"
|
||||
icon="rate_review"
|
||||
class="flex-grow"
|
||||
@@ -199,7 +206,11 @@ async function invite() {
|
||||
v-if="data.isMember"
|
||||
color="danger"
|
||||
:icon="(quest.unreviewed || 0) > 0 ? 'priority_high' : undefined"
|
||||
:to="$localePath(`/hunt/${sluggy(data)}/${sluggy(quest)}/admin`)"
|
||||
:to="
|
||||
$localePath(
|
||||
`/hunt/${tSluggy(data).value}/${tSluggy(quest).value}/admin`
|
||||
)
|
||||
"
|
||||
>Admin ({{ quest.unreviewed || 0 }} unreviewed)</VaButton
|
||||
>
|
||||
</VaCardActions>
|
||||
|
||||
@@ -7,13 +7,14 @@ definePageMeta({
|
||||
const app = useNuxtApp();
|
||||
const { loggedIn } = useUserSession();
|
||||
const { t } = useI18n();
|
||||
const { tKey, hasKey } = useI18nKey();
|
||||
|
||||
const { name, id } = app.$slugData.huntSlug!;
|
||||
|
||||
const titleStore = useTitleStore();
|
||||
|
||||
type Picture = {
|
||||
quest: { id: number; title: string };
|
||||
quest: { id: number; title_de: string; title_en: string };
|
||||
team: {
|
||||
name: string;
|
||||
id: number;
|
||||
@@ -47,7 +48,7 @@ const { data, refresh, error } = await useFetch(`/api/hunt/${id}/diashow`, {
|
||||
|
||||
const cols = pictures.reduce(
|
||||
(c, p, i) => {
|
||||
c[i % 4].push(p);
|
||||
c[i % 4]!.push(p);
|
||||
return c;
|
||||
},
|
||||
new Array(4).fill(0).map(() => [] as Picture[])
|
||||
@@ -59,14 +60,14 @@ const { data, refresh, error } = await useFetch(`/api/hunt/${id}/diashow`, {
|
||||
|
||||
useHead({
|
||||
title: t('layouts.two_title', {
|
||||
title: data.value?.name || name,
|
||||
title: hasKey(data.value, 'name') ? tKey(data.value!, 'name').value : name,
|
||||
subtitle: 'Diashow'
|
||||
})
|
||||
});
|
||||
|
||||
watch(loggedIn, () => refresh());
|
||||
|
||||
titleStore.title = data.value?.name;
|
||||
titleStore.title = data.value ? tKey(data.value, 'name').value : undefined;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -81,7 +82,7 @@ titleStore.title = data.value?.name;
|
||||
:key="pic.picture.url"
|
||||
:src="pic.picture.url"
|
||||
class="h-auto max-w-full rounded-lg"
|
||||
:title="`${pic.quest.title} — ${pic.team.name} — ${pic.picture.creator.name}`"
|
||||
:title="`${tKey(pic.quest, 'title')} — ${pic.team.name} — ${pic.picture.creator.name}`"
|
||||
/>
|
||||
</div>
|
||||
<VaAlert
|
||||
|
||||
@@ -7,6 +7,7 @@ definePageMeta({
|
||||
layout: 'full'
|
||||
});
|
||||
const { t, d } = useI18n();
|
||||
const { tKey, hasKey, tSluggy } = useI18nKey();
|
||||
|
||||
const app = useNuxtApp();
|
||||
const { name, id } = app.$slugData.huntSlug!;
|
||||
@@ -52,7 +53,9 @@ const columns = leaderboardColumns.map((c) =>
|
||||
class="flex flex-col items-center justify-center gap-8 bg-green-300 text-center"
|
||||
>
|
||||
<h1 class="text-7xl">{{ t('page.showcase.showcase_for') }}</h1>
|
||||
<h1 class="text-9xl font-bold">{{ data.name || name }}</h1>
|
||||
<h1 class="text-9xl font-bold">
|
||||
{{ hasKey(data, 'name') ? tKey(data, 'name') : name }}
|
||||
</h1>
|
||||
<p v-if="data.start || data.end" class="flex flex-row gap-4 text-4xl">
|
||||
<span v-if="data.start">{{ d(data.start, fullDate) }}</span
|
||||
><span v-if="data.start && data.end"> – </span
|
||||
@@ -94,11 +97,17 @@ const columns = leaderboardColumns.map((c) =>
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<section v-for="quest in data.quests" :key="quest.id" :id="sluggy(quest)">
|
||||
<section
|
||||
v-for="quest in data.quests"
|
||||
:key="quest.id"
|
||||
:id="tSluggy(quest).value"
|
||||
>
|
||||
<div class="flex flex-col gap-4 bg-yellow-100 p-4">
|
||||
<div class="my-8 flex w-full flex-row justify-around">
|
||||
<h3 class="text-3xl">{{ quest.title }}</h3>
|
||||
<p class="text-xl font-bold">{{ quest.question }}</p>
|
||||
<h3 class="text-3xl">{{ tKey(quest, 'title') }}</h3>
|
||||
<p class="text-xl font-bold" v-if="hasKey(quest, 'question')">
|
||||
{{ tKey(quest, 'question') }}
|
||||
</p>
|
||||
<p v-if="quest.textSolution" class="text-3xl">
|
||||
{{ quest.textSolution }}
|
||||
</p>
|
||||
|
||||
@@ -10,6 +10,7 @@ const app = useNuxtApp();
|
||||
const { loggedIn } = useUserSession();
|
||||
const localePath = useLocalePath();
|
||||
const { t } = useI18n();
|
||||
const { tKey, hasKey } = useI18nKey();
|
||||
const router = useRouter();
|
||||
|
||||
const { name, id } = app.$slugData.huntSlug!;
|
||||
@@ -21,7 +22,7 @@ const { data, pending, refresh } = await useFetch(
|
||||
|
||||
useHead({
|
||||
title: t('layouts.title', {
|
||||
title: data.value?.name || name
|
||||
title: hasKey(data.value, 'name') ? tKey(data.value!, 'name').value : name
|
||||
})
|
||||
});
|
||||
|
||||
@@ -31,7 +32,7 @@ watch(loggedIn, (isLoggedIn) => {
|
||||
}
|
||||
});
|
||||
|
||||
titleStore.title = data.value?.name;
|
||||
titleStore.title = data.value ? tKey(data.value, 'name').value : undefined;
|
||||
|
||||
type Data = NonNullable<(typeof data)['value']>;
|
||||
export type Team = Data['teams'][number];
|
||||
|
||||
Reference in New Issue
Block a user