add turnstile
This commit is contained in:
parent
bd9b4ee2b5
commit
11ab30d0f5
7 changed files with 784 additions and 91 deletions
|
|
@ -36,23 +36,24 @@ const localePath = useLocalePath()
|
|||
<div class="flex flex-col gap-3 justify-between items-start w-fit sm:w-1/2 md:w-fit">
|
||||
<h1 class="text-2xl text-c-blue">{{ t('footer.links.title') }}</h1>
|
||||
<ul class="text-white text-sm">
|
||||
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">{{
|
||||
t('footer.links.success') }}</li>
|
||||
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">{{
|
||||
t('footer.links.articles') }}</li>
|
||||
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">{{
|
||||
t('footer.links.services') }}</li>
|
||||
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">
|
||||
<NuxtLink :to="localePath('/portfolio')"> {{
|
||||
t('footer.links.success') }}</NuxtLink>
|
||||
</li>
|
||||
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">
|
||||
<NuxtLink :to="localePath('/blog')">
|
||||
{{
|
||||
t('footer.links.articles') }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">
|
||||
<NuxtLink :to="localePath('/services')">
|
||||
{{
|
||||
t('footer.links.services') }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- <div class="flex flex-col gap-3 justify-between items-start w-fit sm:w-1/2 md:w-fit">
|
||||
<h1 class="text-2xl text-c-blue">{{ t('footer.socials.title') }}</h1>
|
||||
<ul class="text-white text-sm">
|
||||
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">{{
|
||||
t('footer.socials.linkedin') }}</li>
|
||||
<li class="capitalize cursor-pointer hover:text-c-blue hover:underline">{{
|
||||
t('footer.socials.twitter') }}</li>
|
||||
</ul>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
<hr class="bg-white h-[1px] my-12 w-full">
|
||||
|
|
|
|||
|
|
@ -1,59 +1,97 @@
|
|||
<script setup lang="ts">
|
||||
const { t } = useI18n({ useScope: 'global' })
|
||||
import { useReCaptcha } from 'vue-recaptcha-v3';
|
||||
// import { useReCaptcha } from 'vue-recaptcha-v3';
|
||||
import { useForm } from 'vee-validate';
|
||||
import { toTypedSchema } from '@vee-validate/yup';
|
||||
import * as yup from 'yup';
|
||||
|
||||
const { t, locale } = useI18n({ useScope: 'global' })
|
||||
const localePath = useLocalePath()
|
||||
const newMessage = reactive({
|
||||
name: '',
|
||||
email: '',
|
||||
phone: '',
|
||||
message: '',
|
||||
})
|
||||
|
||||
const recaptchaInstance = useReCaptcha();
|
||||
|
||||
const recaptcha = async () => {
|
||||
// optional you can await for the reCaptcha load
|
||||
await recaptchaInstance?.recaptchaLoaded();
|
||||
const schema = toTypedSchema(
|
||||
yup.object({
|
||||
name: yup.string().trim().min(3).required(),
|
||||
email: yup.string().required().email(),
|
||||
phone: yup.string().required(),
|
||||
message: yup.string().required(),
|
||||
}),
|
||||
);
|
||||
|
||||
// get the token, a custom action could be added as argument to the method
|
||||
const token = await recaptchaInstance?.executeRecaptcha('yourActionHere');
|
||||
const { errors, values, defineField, handleSubmit } = useForm({
|
||||
validationSchema: schema,
|
||||
});
|
||||
|
||||
return token;
|
||||
};
|
||||
const [name, nameAttrs] = defineField('name');
|
||||
const [email, emailAttrs] = defineField('email');
|
||||
const [phone, phoneAttrs] = defineField('phone');
|
||||
const [message, messageAttrs] = defineField('message');
|
||||
|
||||
async function submit(){
|
||||
const token = await recaptcha();
|
||||
const mail = useMail()
|
||||
|
||||
const toggle = ref(false)
|
||||
const token = ref("")
|
||||
|
||||
const turnstile = ref()
|
||||
|
||||
function reset() {
|
||||
turnstile.value?.reset()
|
||||
}
|
||||
|
||||
|
||||
const onSubmit = handleSubmit(async (values) => {
|
||||
// const token = await recaptcha('login')
|
||||
// .then(() => {
|
||||
|
||||
// })
|
||||
toggle.value = !toggle.value
|
||||
mail.send({
|
||||
from: values.email,
|
||||
subject: 'Incredible',
|
||||
text: values.message,
|
||||
})
|
||||
});
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<form action="" class="w-full lg:w-1/3 flex flex-col">
|
||||
<form @submit.prevent="onSubmit" class="w-full lg:w-1/3 flex flex-col">
|
||||
<div class="footer__form__field flex flex-col mb-3">
|
||||
<label for="name">{{ t('footer.form.name') }}</label>
|
||||
<input v-model="newMessage.name" class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400"
|
||||
name="name" type="text" :placeholder="t('footer.form.name_placeholder')">
|
||||
<p class="text-red-500 ml-3 mt-1"></p>
|
||||
<input id="name" v-model="name" v-bind="nameAttrs"
|
||||
class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400" name="name" type="text"
|
||||
:placeholder="t('footer.form.name_placeholder')" autocomplete="username">
|
||||
<p class="text-red-500 ml-3 mt-1 transition-all">
|
||||
{{ errors.name }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="footer__form__field flex flex-col mb-3">
|
||||
<label for="email">{{ t('footer.form.email') }}</label>
|
||||
<input v-model="newMessage.email" class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400"
|
||||
name="email" type="email" :placeholder="`${t('footer.form.email_placeholder')} myname@example.com`">
|
||||
<p class="text-red-500 ml-3 mt-1"></p>
|
||||
<input id="email" v-model="email" v-bind="emailAttrs"
|
||||
class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400" name="email" type="email"
|
||||
:placeholder="`${t('footer.form.email_placeholder')} myname@example.com`" autocomplete="email">
|
||||
<p class="text-red-500 ml-3 mt-1 transition-all">
|
||||
{{ errors.email }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="footer__form__field flex flex-col mb-3">
|
||||
<label for="phone">{{ t('footer.form.phone') }}</label>
|
||||
<input v-model="newMessage.phone" class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400"
|
||||
name="phone" type="tel" :placeholder="t('footer.form.phone_placeholder')">
|
||||
<p class="text-red-500 ml-3 mt-1"></p>
|
||||
<input id="phone" v-model="phone" v-bind="phoneAttrs"
|
||||
class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400" name="phone" type="tel"
|
||||
:placeholder="t('footer.form.phone_placeholder')" autocomplete="tel">
|
||||
<p class="text-red-500 ml-3 mt-1 transition-all">
|
||||
{{ errors.phone }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="footer__form__field flex flex-col mb-3">
|
||||
<label for="name">{{ t('footer.form.message') }}</label>
|
||||
<textarea v-model="newMessage.message" class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400"
|
||||
rows="3" name="message"></textarea>
|
||||
<p class="text-red-500 ml-3 mt-1"></p>
|
||||
<label for="message">{{ t('footer.form.message') }}</label>
|
||||
<textarea id="message" v-model="message" v-bind="messageAttrs"
|
||||
class="bg-transparent p-3 border-b-2 focus:outline-none text-slate-400" rows="3" name="message"></textarea>
|
||||
<p class="text-red-500 ml-3 mt-1 transition-all">
|
||||
{{ errors.message }}
|
||||
</p>
|
||||
</div>
|
||||
<NuxtTurnstile v-if="toggle" ref="turnstile" v-model="token" :key="locale" :options="{ action: 'vue' }" />
|
||||
|
||||
<button class="btn__contact bg-c-blue text-c-darkblue px-7 py-2 uppercase text-xl rounded-full mt-3">
|
||||
<button type="submit" class="btn__contact bg-c-blue text-c-darkblue px-7 py-2 uppercase text-xl rounded-full mt-3">
|
||||
{{ t('footer.form.btn_form') }}
|
||||
</button>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,17 @@ export default defineNuxtConfig({
|
|||
"@dargmuesli/nuxt-cookie-control",
|
||||
'@nuxt/content',
|
||||
'@nuxthq/studio',
|
||||
'@vueuse/motion/nuxt'
|
||||
'@vueuse/motion/nuxt',
|
||||
['nuxt-mail', {
|
||||
message: {
|
||||
to: 'foo@bar.de',
|
||||
},
|
||||
smtp: {
|
||||
host: "smtp.example.com",
|
||||
port: 587,
|
||||
},
|
||||
}],
|
||||
'@nuxtjs/turnstile'
|
||||
],
|
||||
app: {
|
||||
pageTransition: { name: 'page', mode: 'out-in' }
|
||||
|
|
@ -41,6 +51,7 @@ export default defineNuxtConfig({
|
|||
cookieKey: "i18n_redirected",
|
||||
redirectOn: "root",
|
||||
alwaysRedirect: true,
|
||||
cookieCrossOrigin: true
|
||||
},
|
||||
},
|
||||
cookieControl: {
|
||||
|
|
@ -53,5 +64,5 @@ export default defineNuxtConfig({
|
|||
},
|
||||
content: {
|
||||
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
696
package-lock.json
generated
696
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -12,6 +12,7 @@
|
|||
"devDependencies": {
|
||||
"@dargmuesli/nuxt-cookie-control": "^7.2.4",
|
||||
"@nuxthq/studio": "^1.0.10",
|
||||
"@nuxtjs/turnstile": "^0.6.3",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"nuxt": "^3.8.2",
|
||||
"nuxt-aos": "^1.2.2",
|
||||
|
|
@ -25,7 +26,9 @@
|
|||
"dependencies": {
|
||||
"@nuxt/content": "^2.11.0",
|
||||
"@nuxtjs/i18n": "^8.0.0",
|
||||
"@vee-validate/yup": "^4.12.5",
|
||||
"@vueuse/motion": "^2.0.0",
|
||||
"vue-recaptcha-v3": "^2.0.1"
|
||||
"nuxt-mail": "^4.0.2",
|
||||
"vee-validate": "^4.12.5"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
const cookieControl = useCookieControl()
|
||||
|
||||
if (cookieControl.cookiesEnabledIds.value.includes('google-analytics')) {
|
||||
initGoogleAnalytics() // placeholder for your custom initialization
|
||||
}
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
const cookieControl = useCookieControl()
|
||||
|
||||
if (cookieControl.cookiesEnabledIds.value?.includes('google-analytics')) {
|
||||
initGoogleAnalytics() // placeholder for your custom initialization
|
||||
}
|
||||
})
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
import { VueReCaptcha } from 'vue-recaptcha-v3';
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
nuxtApp.vueApp.use(VueReCaptcha, {
|
||||
siteKey: '6Le062UpAAAAAEsjplkXWsQIiDzO_sVICajoqPk2',
|
||||
loaderOptions: {
|
||||
autoHideBadge: false,
|
||||
explicitRenderParameters: {
|
||||
badge: 'bottomright',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue