marc-leopold/pages/contact.vue

284 lines
6.3 KiB
Vue
Raw Normal View History

2019-01-14 10:24:29 +00:00
<template>
2019-01-27 18:26:13 +00:00
<ContentPage heading="Contact Me">
<form class="contact-form">
<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 ...">
</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>
2019-01-27 19:02:43 +00:00
<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>
2019-01-27 18:26:13 +00:00
</div>
</form>
<BackgroundImageLoader slot="background"
class="background"
2019-02-04 11:53:23 +00:00
:image-url="imageUrl"
2019-01-27 18:26:13 +00:00
>
<div slot="overlay" class="background-tint background-overlay"></div>
</BackgroundImageLoader>
2019-01-14 10:24:29 +00:00
</ContentPage>
</template>
<script>
import ContentPage from '@/components/ContentPage'
2019-01-14 13:10:29 +00:00
import { required, email } from 'vuelidate/lib/validators'
2019-01-27 18:26:13 +00:00
import BackgroundImageLoader from '@/components/BackgroundImageLoader'
2019-01-14 10:24:29 +00:00
export default {
2019-01-31 10:20:14 +00:00
name: 'ContactPage',
2019-01-14 10:24:29 +00:00
components: {
2019-01-27 18:26:13 +00:00
ContentPage,
BackgroundImageLoader,
2019-01-14 10:24:29 +00:00
},
data() {
return {
2019-01-14 13:10:29 +00:00
attemptedSubmit: false,
form: {
name: "",
email: "",
subject: "",
message: "",
2019-01-27 19:02:43 +00:00
},
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' },
],
2019-01-14 13:10:29 +00:00
}
},
2019-01-31 10:20:14 +00:00
head () {
return {
title: 'Contact Me',
2019-02-04 12:53:18 +00:00
meta: [{
hid: 'description',
name: 'description',
content: 'Contact the photographer Marc Leopold with any queries for a prompt response.'
}],
2019-01-31 10:20:14 +00:00
}
},
2019-01-14 13:10:29 +00:00
computed: {
isDisabled () {
return this.attemptedSubmit && this.$v.form.$invalid
}
},
validations: {
form: {
name: {
required,
},
email: {
required,
email
},
message: {
required,
}
2019-01-14 10:24:29 +00:00
}
2019-01-14 11:31:17 +00:00
},
methods: {
onSubmit () {
2019-01-14 13:10:29 +00:00
this.attemptedSubmit = true
if (this.$v.form.$invalid) {
this.$toast.open({
message: 'Please correct errors before submitting.',
type: 'is-danger'
})
return
}
this.$toast.open('Submitting your message ...')
window.setTimeout(() => {
this.$toast.open({
message: 'Thank you, your message has been succesfully sent.',
type: 'is-success'
})
this.form.message = ''
this.form.subject = ''
}, 1000)
2019-01-14 11:31:17 +00:00
},
},
2019-02-04 11:53:23 +00:00
2019-02-12 12:41:44 +00:00
async asyncData ({ $axios }) {
2019-02-15 11:05:14 +00:00
try {
const { imageUrl } = await $axios.$get('/api/v1/page/about')
if (!imageUrl) {
throw new Error('empty imageUrl')
}
return { imageUrl }
} catch {
return {
imageUrl: '/img/default-contact.jpg'
}
}
2019-02-04 11:53:23 +00:00
},
2019-01-14 10:24:29 +00:00
}
</script>
<style scoped lang="scss">
2019-01-27 18:26:13 +00:00
.contact-form {
2019-01-30 21:21:55 +00:00
width: 100%;
2019-01-27 18:26:13 +00:00
padding: 1rem 1rem 2rem;
border-radius: 2px;
2019-01-30 20:35:05 +00:00
background-color: rgba(#fff, .9);
2019-01-27 18:26:13 +00:00
background: linear-gradient(
to bottom right,
2019-01-30 20:35:05 +00:00
rgba(#fff, .95),
2019-01-27 18:26:13 +00:00
rgba($color__neutral-800, .9)
),
2019-01-31 10:27:50 +00:00
url(/img/keyboard--crop-rotate.jpg);
2019-01-27 18:26:13 +00:00
background-size: cover;
background-position: center center;
@media (min-width: $bp__layout) {
padding: 2rem;
}
}
.form-content {
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;
}
}
2019-01-27 19:02:43 +00:00
.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;
}
}
2019-01-14 10:24:29 +00:00
</style>