Skip to content

Commit

Permalink
Finished Contact tab
Browse files Browse the repository at this point in the history
Added send email with EmailJS
Fixed responsive problems in Skills tab
Added transition effect when change tab
Fixed problem with scroll when change tab
  • Loading branch information
MacKey-255 committed Jul 27, 2023
1 parent 728b05d commit f341d0c
Show file tree
Hide file tree
Showing 10 changed files with 273 additions and 17 deletions.
208 changes: 205 additions & 3 deletions components/tabs/Contact.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,217 @@
<template>
<div class="mx-auto">
<page-header icon="envelope-open" title="contact"/>
<div class="sm:mt-8"></div>
<div class="grid gap-x-10 md:gap-y-6 md:grid-cols-2">
<div class="md:col-span-1 md:px-6 py-3">
<!--Introduction-->
<div class="mb-4 lg:col-span-2 lg:w-full lg:max-w-7xl lg:gap-x-8">
<div class="lg:pr-4">
<h1 class="mt-2 text-4xl font-bold tracking-tight text-gray-900 dark:text-gray-200">
{{ $t('contact_title') }}
</h1>
<p class="mt-3 text-xl leading-8 text-gray-700 dark:text-gray-200">
{{ $t('contact_subtitle') }}
</p>
</div>
</div>

<!-- LinkedIn -->
<div class="md:pr-6 py-2 flex gap-x-3">
<font-awesome-icon class="my-auto md:mx-2 flex-none contact-icon text-gray-800 dark:text-gray-300"
:icon="['fab', 'linkedin']"/>
<div>
<div class="font-bold text-gray-900 dark:text-gray-200 text-xl mb-1">
{{ $t('contact_linkedin_profile') }}
</div>
<a :href="linkedin_url"
class="font-bold text-blue-500 text-xl mb-2"
target="_blank"
rel="noreferrer"
aria-label="linkedin url">
{{ $store.getters.LINKEDIN_PROFILE_URL }}
</a>
</div>
</div>

<!-- Github -->
<div class="md:pr-6 py-2 flex gap-x-3">
<font-awesome-icon class="my-auto md:mx-2 flex-none contact-icon text-gray-800 dark:text-gray-300"
:icon="['fab', 'github']"/>
<div>
<div class="font-bold text-gray-900 dark:text-gray-200 text-xl mb-1">
{{ $t('contact_github_profile') }}
</div>
<a :href="$store.getters.GITHUB_PROFILE_URL" class="font-bold text-blue-500 text-xl mb-2"
target="_blank"
rel="noreferrer"
aria-label="github url">
{{ $store.getters.GITHUB_PROFILE_URL }}
</a>
</div>
</div>

<!-- Phone -->
<div class="md:pr-6 py-2 flex gap-x-3">
<font-awesome-icon class="my-auto md:mx-2 flex-none contact-icon text-gray-800 dark:text-gray-300"
:icon="['fas', 'phone']"/>
<div>
<div class="font-bold text-gray-900 dark:text-gray-200 text-xl mb-1">
{{ $t('contact_phone') }}
</div>
<a :href="tel_phone" class="font-bold text-blue-500 text-xl mb-2">
{{ phone }}
</a>
</div>
</div>

<!-- Email -->
<div class="md:pr-6 py-2 flex gap-x-3">
<font-awesome-icon class="my-auto md:mx-2 flex-none contact-icon text-gray-800 dark:text-gray-300"
:icon="['fas', 'envelope']"/>
<div>
<div class="font-bold text-gray-900 dark:text-gray-200 text-xl mb-1">
{{ $t('contact_email') }}
</div>
<a :href="email" class="font-bold text-blue-500 text-xl mb-2"
target="_blank"
rel="noreferrer"
aria-label="email url">
{{ $store.getters.EMAIL }}
</a>
</div>
</div>
</div>

<div class="md:col-span-1 md:px-6 py-3">
<div class="mb-4 lg:col-span-2 lg:w-full lg:max-w-7xl lg:gap-x-8">
<div class="lg:pr-4">
<h1 class="mt-2 text-4xl font-bold tracking-tight text-gray-900 dark:text-gray-200">
{{ $t('contact_form') }}:
</h1>
</div>
</div>
<div class="w-full flex">
<form class="w-full xl:w-4/5 flex flex-col gap-4 justify-center items-center" @submit.prevent="send_email">
<div class="w-full flex flex-col md:flex-row gap-4">
<div class="w-full md:w-6/12 flex flex-col">
<label class="mb-2 text-gray dark:text-white" for="name">{{ $t('contact_email_name') }}</label>
<input required=""
title="Name"
name="name"
:placeholder="$t('contact_email_name_placeholder')"
v-model="form.name"
class="p-2 text-gray border-solid border-slate-200 dark:border-gray-700 border
rounded bg-white dark:text-white dark:bg-gray-800 focus:outline outline-blue-500 outline-2
focus:border-blue-500">
</div>
<div class="w-full md:w-6/12 flex flex-col">
<label class="mb-2 text-gray dark:text-white" for="email">{{ $t('contact_email') }}</label>
<input required=""
title="Email"
type="email"
name="email"
placeholder="me@mail.com"
v-model="form.email"
class="p-2 text-gray border-solid border-slate-200 dark:border-gray-700 border
rounded bg-white dark:text-white dark:bg-gray-800 focus:outline outline-blue-500 outline-2
focus:border-blue-500">
</div>
</div>
<div class="w-full flex flex-col">
<label class="mb-2 text-gray dark:text-white" for="message">{{ $t('contact_email_message') }}</label>
<textarea name="message"
required=""
rows="5"
:placeholder="$t('contact_email_message_placeholder')"
v-model="form.message"
class="resize-none p-2 text-gray border-solid border-slate-200 dark:border-gray-700 border
rounded bg-white dark:text-white dark:bg-gray-800 focus:outline outline-blue-500 outline-2
focus:border-blue-500"></textarea>
</div>

<div class="flex items-center rounded-full bg-teal-200 text-teal-900 text-sm font-bold px-4 py-3"
role="alert" v-if="sending">
<font-awesome-icon class="text-teal-500 text-lg mr-2" :icon="['fas', 'check']"/>
<p>{{$t('contact_email_sent')}}</p>
</div>
<div class="flex items-center rounded-full bg-red-200 text-red-900 text-sm font-bold px-4 py-3"
role="alert" v-if="error">
<font-awesome-icon class="text-red-500 text-md mr-2" :icon="['fas', 'x']"/>
<p>{{$t('contact_email_sent_error')}}</p>
</div>

<div class="w-full">
<button class="bg-blue-500 w-100 block text-white p-2 w-full rounded-lg">
{{ $t('contact_email_send') }}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</template>

<script>
import emailjs from '@emailjs/browser';
export default {
name: "Contact"
name: "Contact",
data() {
return {
phone: '+34 604256897',
form: {
name: '',
email: '',
message: '',
},
sending: false,
error: false,
}
},
computed: {
tel_phone() {
return 'tel:' + this.phone;
},
linkedin_url() {
return this.$store.getters.LINKEDIN_PROFILE_URL + '?locale=' + (this.$i18n.locale === 'en' ? 'en_US' : 'es_ES');
},
email() {
let subject = 'Oferta%20de%20trabajo';
if (this.$i18n.locale === 'en') {
subject = 'Work%20offer';
}
return 'mailto:' + this.$store.getters.EMAIL + '?Subject=' + subject;
}
},
methods: {
send_email() {
emailjs.send('portfolio', 'template_portfolio', {
user_name: this.form.name, user_email: this.form.email, message: this.form.message
}, 'u0e_FkHOlD75wLr8g')
.then((_) => {
this.sending = true;
this.clear_email();
setTimeout(() => {this.sending = false}, 5000);
}, (_) => {
this.error = true;
this.clear_email();
setTimeout(() => {this.error = false}, 5000);
});
},
clear_email() {
this.form = {
name: '',
email: '',
message: '',
};
}
}
}
</script>

<style scoped>
.contact-icon {
font-size: 32px;
}
</style>
4 changes: 2 additions & 2 deletions components/tabs/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
</a>

<a class="transition ease-in-out hover:scale-150 hover:-translate-y-1 duration-150"
:href="get_email"
:href="email"
target="_blank"
rel="noreferrer"
aria-label="send email">
Expand Down Expand Up @@ -82,7 +82,7 @@ import {mapMutations} from "vuex";
export default {
name: "Home",
computed: {
get_email() {
email() {
let subject = 'Oferta%20de%20trabajo';
if (this.$i18n.locale === 'en') {
subject = 'Work%20offer';
Expand Down
12 changes: 6 additions & 6 deletions components/tabs/Skills.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<template>
<div class="mx-auto">
<div class="sm:mt-8"></div>
<div class="grid gap-x-10 gap-y-6 md:grid-cols-3 lg:grid-cols-2">
<div class="md:col-span-2 lg:col-span-1">
<div class="grid gap-x-10 gap-y-6 md:grid-cols-3 xl:grid-cols-2">
<div class="md:col-span-2 xl:col-span-1">
<!--Introduction-->
<div class="lg:col-span-2 lg:mx-auto lg:w-full lg:max-w-7xl lg:gap-x-8">
<div class="lg:col-span-2 lg:w-full lg:max-w-7xl lg:gap-x-8">
<div class="lg:pr-4">
<h1 class="mt-2 text-4xl font-bold tracking-tight text-gray-900 dark:text-gray-200">
{{ $t('skills_title') }}
Expand Down Expand Up @@ -37,14 +37,14 @@

<div class="md:col-span-1">
<!--Skills-->
<div class="lg:col-span-2 lg:mx-auto lg:w-full lg:max-w-7xl lg:gap-x-8 lg:px-8 mb-6"
<div class="lg:col-span-2 lg:w-full md:max-w-lg lg:gap-x-8 lg:px-8 mb-6"
v-for="skill in skills">
<div class="lg:pr-4">
<h1 class="md:mt-2 text-xl font-bold tracking-tight text-gray-900 dark:text-gray-200">
{{ $t(skill.label) }}:
</h1>
<div class="flex flex-wrap mt-3 gap-2">
<div v-for="item in skill.list" class="hover:scale-125 ease-in-out duration-150">
<div v-for="item in skill.list" class="hover:scale-125 ease-in-out duration-150 mb-1">
<!--span
class="pl-3 py-1.5
font-semibold text-sm bg-gray-300/[0.8] dark:bg-slate-600/[0.8] dark:text-white
Expand All @@ -64,7 +64,7 @@
</div>

<!--Languages-->
<div class="md:mt-8 mb-4 lg:col-span-2 lg:mx-auto lg:w-full lg:max-w-7xl lg:gap-x-8 lg:px-8">
<div class="md:mt-8 mb-4 lg:col-span-2 lg:w-full md:max-w-lg lg:gap-x-8 lg:px-8">
<div class="lg:pr-4">
<h1 class="md:mt-2 text-xl font-bold tracking-tight text-gray-900 dark:text-gray-200">
{{ $t('skills_title_languages') }}:
Expand Down
9 changes: 8 additions & 1 deletion layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<particles :is-dark-mode="isDarkMode"/>
<AppMenu/>

<div class="container px-4 md:mx-auto">
<div class="container px-4 sm:mx-auto">
<NuxtChild/>
</div>
<AppFooter/>
Expand Down Expand Up @@ -38,4 +38,11 @@ export default {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: saturate(180%) blur(10px);
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
.fade-enter-active, .fade-leave-active {
transition: opacity 0.1s ease-in-out;
}
</style>
16 changes: 16 additions & 0 deletions locales/en-US.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,22 @@ export default {
skills_title_languages: 'Languages',
skills_languages: [['Spanish', '(Native)'], ['English', '(A2)']],
/* Projects */
/* Contacts */
contact_title: 'Have a Project in Mind? Let\'s Build Something Great Together!',
contact_subtitle: 'I\'m excited to hear from you and discuss how we can collaborate to bring your ideas to life. Whether it\'s a web application, API development or any other web solution, let\'s turn your ideas into reality and make an impact in the digital world. Contact me now to get started!',
contact_linkedin_profile: 'LinkedIn Profile',
contact_github_profile: 'Github Profile',
contact_phone: 'Phone',
contact_form: 'Contact me',

contact_email: 'Email',
contact_email_name: 'Name',
contact_email_name_placeholder: 'Enter Name',
contact_email_message: 'Message',
contact_email_message_placeholder: 'Type a message...',
contact_email_send: 'Submit',
contact_email_sent: 'Message sent successfully!',
contact_email_sent_error: 'Error sending message!',
/* Utils */
years: 'yrs',
year: 'yr',
Expand Down
16 changes: 16 additions & 0 deletions locales/es-ES.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,22 @@ export default {
skills_title_languages: 'Idiomas',
skills_languages: [['Español', '(Nativo)'], ['Ingles', '(A2)']],
/* Projects */
/* Contacts */
contact_title: '¿Tienes un proyecto en mente? ¡Construyamos algo grandioso juntos!',
contact_subtitle: 'Estoy emocionado por saber de ti y hablar cómo podemos colaborar para dar vida a tus ideas. Ya sea una aplicación web, desarrollo de API o cualquier otra solución web, convertamos tus ideas en realidad y hagamos un impacto en el mundo digital. ¡Contáctame ahora para empezar!',
contact_linkedin_profile: 'Perfil LinkedIn',
contact_github_profile: 'Perfil Github',
contact_phone: 'Teléfono',
contact_form: 'Contactame',

contact_email: 'Correo',
contact_email_name: 'Nombre',
contact_email_name_placeholder: 'Introduzca el nombre',
contact_email_message: 'Mensaje',
contact_email_message_placeholder: 'Escribe un message...',
contact_email_send: 'Enviar',
contact_email_sent: '¡Mensaje enviado exitosamente!',
contact_email_sent_error: '¡Error enviando el mensaje!',
/* Utils */
years: 'años',
year: 'año',
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"generate": "nuxt generate"
},
"dependencies": {
"@emailjs/browser": "^3.11.0",
"@nuxtjs/i18n": "^7.3.1",
"core-js": "^3.25.3",
"nuxt": "^2.15.8",
Expand Down
14 changes: 10 additions & 4 deletions pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
<template>
<main class="tab-content flex md:h-screen">
<Skills v-if="isActive(2)"/>
<Portfolio v-else-if="isActive(3)"/>
<Contact v-else-if="isActive(4)"/>
<Home v-else/>
<transition name="fade" mode="out-in">
<Skills v-if="isActive(2)"/>
<Portfolio v-else-if="isActive(3)"/>
<Contact v-else-if="isActive(4)"/>
<Home v-else/>
</transition>
</main>
</template>

Expand All @@ -29,6 +31,10 @@ export default {
</script>

<style scoped>
main {
will-change: transform, opacity;
}
.tab-content {
padding-bottom: 24px; /* Footer separation */
}
Expand Down
5 changes: 4 additions & 1 deletion store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ export const mutations = {
SET_DARK: (state, bool) => {
if (process.client) {
localStorage.setItem('dark-theme', bool);
state.isDarkMode = bool;
}
state.isDarkMode = bool;
},
SET_PAGE: (state, value) => {
state.activePage = value;
if (process.client) {
window.scrollTo(0, 0);
}
}
};
Loading

0 comments on commit f341d0c

Please sign in to comment.