Switch to translatable data

This commit is contained in:
2025-08-20 23:18:40 +02:00
parent c35fb06830
commit cc544322b2
36 changed files with 431 additions and 146 deletions
@@ -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>
+34 -17
View File
@@ -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>