marc-leopold/app/pages/contact.vue

323 lines
7.1 KiB
Vue

<template>
<ContentPage :heading="title">
<form class="contact-form">
<div class="form-background"></div>
<div class="form-content">
<b-field label="Name"
:type="attemptedSubmit && form.name.length < 1 ? 'is-danger' : ''"
:message="attemptedSubmit && form.name.length < 1 ? 'Please include your name.' : ''"
>
<b-input v-model.trim="form.name"
@input="$v.form.name.$touch()"
placeholder="Your name ...">
</b-input>
</b-field>
<b-field label="Email"
:type="attemptedSubmit && form.email.length < 1 ? 'is-danger' : ''"
:message="attemptedSubmit && form.email.length < 1 ? 'Please include your email address.' : ''"
>
<b-input v-model="form.email"
type="email"
placeholder="Your email address ...">
</b-input>
</b-field>
<b-field label="Subject">
<b-input v-model="form.subject"
placeholder="Your subject ...">
</b-input>
</b-field>
<b-field label="Message"
:type="attemptedSubmit && form.message.length < 1 ? 'is-danger' : ''"
:message="attemptedSubmit && form.message.length < 1 ? 'Please include a message.' : ''"
>
<b-input v-model="form.message"
placeholder="Your message ..."
type="textarea">
</b-input>
</b-field>
<div class="form-footer">
<button class="btn-submit"
type="button"
@click.prevent="onSubmit"
:disabled="isDisabled">
Send
</button>
<ul class="social-nav">
<li v-for="item in socialNav"
:key="item.to"
class="social-nav__item"
>
<a class="social-nav__link social-link"
:href="item.to"
target="_blank"
>
<b-icon class="social-nav__icon"
:icon="item.icon"
/>
</a>
</li>
</ul>
</div>
</div>
</form>
<BackgroundImageLoader slot="background"
class="background"
:image-url="imageUrl"
>
<div slot="overlay" class="background-tint background-overlay"></div>
</BackgroundImageLoader>
</ContentPage>
</template>
<script>
import ContentPage from '@/components/ContentPage'
import { required, email } from 'vuelidate/lib/validators'
import BackgroundImageLoader from '@/components/BackgroundImageLoader'
export default {
name: 'ContactPage',
components: {
ContentPage,
BackgroundImageLoader,
},
data() {
return {
attemptedSubmit: false,
form: {
name: "",
email: "",
subject: "",
message: "",
},
socialNav: [
{ 'to': 'https://www.instagram.com', 'text': 'Instagram', icon: 'instagram' },
{ 'to': 'https://www.facebook.com', 'text': 'Facebook', icon: 'facebook' },
{ 'to': 'https://twitter.com', 'text': 'Twitter', icon: 'twitter' },
{ 'to': 'https://uk.linkedin.com', 'text': 'LinkedIn', icon: 'linkedin' },
],
}
},
head () {
return {
title: this.title,
meta: [{
hid: 'description',
name: 'description',
content: 'Contact the photographer Marc Leopold with any queries for a prompt response.'
}],
}
},
computed: {
isDisabled () {
return this.attemptedSubmit && this.$v.form.$invalid
}
},
validations: {
form: {
name: {
required,
},
email: {
required,
email
},
message: {
required,
}
}
},
methods: {
onSubmit () {
this.attemptedSubmit = true
if (this.$v.form.$invalid) {
this.$toast.open({
message: 'Please correct errors before submitting.',
type: 'is-danger'
})
} else {
this.$toast.open('Submitting your message ...')
this.submitForm()
}
},
async submitForm() {
try {
await this.$axios({
method: 'post',
baseURL: 'http://192.168.0.5:3003',
url: '/api/contact',
proxy: false,
debug: true,
data: {
name: this.form.name,
email: this.form.email,
msg: this.form.message
},
})
} catch (e) {
this.$toast.open({
message: 'sorry, there was a problem submitting your message.',
type: 'is-danger'
})
console.error(e)
return
}
this.$toast.open({
message: 'Thank you, your message has been sent.',
type: 'is-success'
})
this.form.message = ''
this.form.subject = ''
},
},
async asyncData ({ $axios }) {
try {
let { imageUrl, title } = await $axios.$get('/api/v1/page/about')
if (!imageUrl) {
throw new Error('empty imageUrl')
}
if (!title || title === '') {
title = 'Contact Me'
}
return { imageUrl, title }
} catch {
return {
imageUrl: '/img/default-contact.jpg',
title: 'Contact Me',
}
}
},
}
</script>
<style scoped lang="scss">
.contact-form {
position: relative;
width: 100%;
padding: 1rem 1rem 2rem;
border-radius: 2px;
@media (min-width: $bp__layout) {
padding: 2rem;
}
}
.form-background {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(#fff, .95);
background: linear-gradient(
to bottom right,
rgba(#fff, .95),
rgba($color__neutral-800, .97)
),
url(/img/default-contact.jpg);
background-size: cover;
background-position: top left;
transform: scaleX(-1);
}
.form-content {
z-index: 5;
max-width: 30em;
margin: 0 auto;
}
.background-overlay {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.btn-submit {
font-size: 1.2em;
border: 2px solid $color__neutral-300;
padding: .2em .8em;
@include font-title(600);
color: $color__neutral-500;
cursor: pointer;
transition: opacity .3s;
opacity: .7;
&:hover {
opacity: 1;
}
&:disabled {
opacity: .1;
cursor: auto;
}
}
.form-footer {
position: relative;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding-top: 2rem;
margin-top: 2rem;
&::before {
content: '';
position: absolute;
width: 90%;
height: 1px;
top: 0;
left: 5%;
background-color: $color__neutral-800;
}
}
.social-nav {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
}
.social-nav__item {
margin: 0 .2em;
}
.social-link {
transition: opacity .3s;
&:link, &:visited {
color: $color__neutral-100;
opacity: .6;
}
&:hover, &:active {
opacity: 1;
}
}
</style>