323 lines
7.1 KiB
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>
|
|
|