Files
framit/app/pages/contact.vue

154 lines
5.0 KiB
Vue
Raw Permalink Normal View History

2025-11-19 22:03:35 +01:00
<template>
<NuxtLayout name="default">
<UPage>
<h1 class="text-4xl text-highlighted font-bold mb-8">
{{ $t('pages.contact.name') }}
</h1>
<UPageCard class="bg-background-100">
<UForm :schema="schema" :state="state" class="space-y-4" @submit="submitContactForm">
<div class="flex flex-row w-full gap-5">
<UFormField
:label="$t('pages.contact.form.labels.name')"
name="name"
class="w-full"
:ui="{ label: 'text-text text-lg text-bold' }"
>
<UInput
v-model="state.name"
autofocus
:ui="{
root: 'relative inline-flex items-center w-full',
base: 'placeholder:text-300',
}"
required
:placeholder="$t('pages.contact.form.placeholders.name')"
/>
</UFormField>
<UFormField
:label="$t('pages.contact.form.labels.email')"
name="email"
class="w-full"
:ui="{ label: 'text-text text-lg text-bold' }"
>
<UInput
v-model="state.email"
type="email"
:ui="{
root: 'relative inline-flex items-center w-full',
base: 'placeholder:text-300',
}"
required
:placeholder="$t('pages.contact.form.placeholders.email')"
/>
</UFormField>
</div>
<UFormField
class="w-full sr-only"
2025-11-19 22:03:35 +01:00
name="website"
:label="$t('pages.contact.form.labels.website')"
2025-11-19 22:03:35 +01:00
:ui="{ label: 'text-text text-lg text-bold' }"
tabindex="-1"
2025-11-19 22:03:35 +01:00
>
<div>
If you see this input, you may be using accessibility tools to access this website. This input is meant to
be hidden to human visitors, but not bots which do not necessarily render the website the way it is meant
to. Unfortunately, this also affects accessibility tools, such as the ones for visually-impared people. If
that is indeed, please ignore this input, as it is not meant to be filled by human beings. Filling this
input will result in a discarded contact form.
</div>
2025-11-19 22:03:35 +01:00
<UInput
v-model="state.website"
2025-11-19 22:03:35 +01:00
:ui="{ root: 'relative inline-flex items-center w-full', base: 'placeholder:text-300' }"
:placeholder="$t('pages.contact.form.placeholders.website')"
tabindex="-1"
2025-11-19 22:03:35 +01:00
/>
</UFormField>
<UFormField
:label="$t('pages.contact.form.labels.message')"
name="message"
:ui="{ label: 'text-text text-lg text-bold' }"
>
<UTextarea
v-model="state.message"
:ui="{
root: 'relative inline-flex items-center w-full',
base: 'placeholder:text-300',
}"
:placeholder="$t('pages.contact.form.placeholders.message')"
/>
</UFormField>
<UButton
icon="mdi:send-outline"
color="primary"
type="submit"
class="w-full text-center text-lg justify-center-safe"
size="lg"
:loading="loading"
2025-11-19 22:03:35 +01:00
>
{{ $t('pages.contact.form.sendButton') }}
</UButton>
</UForm>
</UPageCard>
</UPage>
</NuxtLayout>
</template>
<script setup lang="ts">
import type { FormSubmitEvent } from '@nuxt/ui';
import { z } from 'zod';
useMeta({
title: $t('pages.contact.name'),
description: $t('pages.contact.description'),
});
const toast = useToast();
2025-11-19 22:03:35 +01:00
const { postContact } = useBackend();
const schema = z.object({
email: z.email($t('pages.contact.form.validation.invalidEmail')),
name: z
.string()
.min(1, $t('pages.contact.form.validation.shortName'))
.max(100, $t('pages.contact.form.validation.longName')),
message: z
.string()
.min(10, $t('pages.contact.form.validation.shortMessage'))
.max(5000, $t('pages.contact.form.validation.longMessage')),
website: z.string().optional(),
});
type Schema = z.output<typeof schema>;
const state = reactive<Partial<Schema>>({
name: undefined,
email: undefined,
message: undefined,
website: undefined,
});
const { data: contactResponse, error: contactError, loading, run: sendRequest } = postContact();
const submitContactForm = async (event: FormSubmitEvent<Schema>) => await sendRequest!(event.data);
watch(contactResponse, async (response) => {
if (response) {
toast.add({
title: response.success ? $t('pages.contact.toast.success') : $t('pages.contact.toast.error'),
description: $t(response.message),
color: response.success ? 'info' : 'error',
});
}
});
watch(contactError, async (response) => {
if (response) {
toast.add({
title: $t('pages.contact.toast.error'),
description: $t(response.message),
color: 'error',
});
}
2025-11-19 22:03:35 +01:00
});
</script>