Compare commits

...

1 Commits

Author SHA1 Message Date
dd31944bc5 Worked on the contact system 2025-04-01 17:51:40 +02:00
6 changed files with 170 additions and 3 deletions

View File

@@ -94,5 +94,30 @@
"desc": "When working with AI, creating a high-quality dataset for training is vital. Many operations and transformations need to be executed, which require a solid understanding of data management. Some infrasctructures also come with databases containing valuable information, that should be extracted and analysed to extract the best from it." "desc": "When working with AI, creating a high-quality dataset for training is vital. Many operations and transformations need to be executed, which require a solid understanding of data management. Some infrasctructures also come with databases containing valuable information, that should be extracted and analysed to extract the best from it."
} }
} }
},
"contact": {
"title": "Send me a message !",
"subtitle": "Thanks for your interest ! If you wish to contact me, the easiest way is by Email.",
"captcha":{
"title": "Sorry, but could you check that you're an human ?",
"desc": "Some bots are exploring the web to collect email adresses and send spam. In order to avoid this, please fill the following :",
"question": "If we add {x} and {y} minus {z}, what would the result be ?",
"submit": "Submit",
"false": "Sorry, this doesn't seems right !"
},
"emails": {
"work" :{
"title": "Work",
"desc": "If your message is about a job opportunity, a company or some professional matter, please use {email}"
},
"school" :{
"title": "Academics and research",
"desc": "{email} is the best suited to talk about universities and research."
},
"others" :{
"title": "Other cases",
"desc": "In case the two previous emails don't suit your needs, you can also use {email}. This address is considered to be a general purposes one."
}
}
} }
} }

View File

@@ -0,0 +1,98 @@
<template>
<div v-if="isHuman">
<h2>{{ $t("contact.emails.work.title") }}</h2>
<p>{{ $t("contact.emails.work.desc", {email:mail1}) }}</p>
<h2>{{ $t("contact.emails.school.title") }}</h2>
<p>{{ $t("contact.emails.school.desc", {email:mail2}) }}</p>
<h2>{{ $t("contact.emails.others.title") }}</h2>
<p>{{ $t("contact.emails.others.desc", {email:mail3}) }}</p>
</div>
<div v-else>
<h2>{{ $t("contact.captcha.title") }}</h2>
<p>{{ $t("contact.captcha.desc") }}</p>
<p v-if="isFalse">{{ $t("contact.captcha.false") }}</p>
<label for="captcha">{{ $t("contact.captcha.question", {x:x, y:y, z:z}) }}</label>
<input type="number" id="captcha" v-model="captchaValue"/>
<button class="button" @click="captchaSubmit">{{ $t("contact.captcha.submit") }}</button>
</div>
</template>
<script setup>
import { onBeforeMount, ref } from 'vue';
const validationChar = "&"; // Used to check that provided number is valid
const x = 7;
const y =20;
const z = 1;
let mail1 = ref("");
let mail2 = ref("");
let mail3 = ref("");
let captchaValue = ref(0);
let isHuman = ref(false);
let isFalse = ref(false);
onBeforeMount(()=>{
});
const captchaSubmit = ()=>{
if(ceasarEncryption(validationChar, captchaValue.value) == "@"){
//OK
isFalse.value = false;
isHuman;value = true;
readEmails();
}else{
isFalse.value = true;
}
};
const readEmails = ()=>{
for(let i=0; i<encryptedEmails.length; i++){
const letter = ceasarEncryption(encryptedEmails[i], 26);
if(letter == "*") continue;
if(i%3==0){
//mail1.value= mail1.value+letter;
}else if(i%3==1){
//mail2.value = mail2.value+letter;
}else{
//mail3.value = mail3.value+letter;
}
if(i%3==1)console.log(letter);
}
}
const ceasarEncryption = (input, gap)=>{
return String.fromCharCode(input.charCodeAt(0) + gap);
}
const encodeEmails = (emails, key)=>{
let output = "";
let i=0;
let j=0;
let letterIndex=0;
while(true){
const mail = emails[i%emails.length];
let end = true;
if(j<mail.length){
//still letters to add
output+=ceasarEncryption(mail[j], key);
end=false;
}else{
output+=ceasarEncryption('*', key);
}
i++;
if(end)break;
if(i%emails.length == emails.length-1)j++; // Looped through all emails, next letter
}
return output;
}
</script>
<style scoped>
label{
color: #EAEAEA;
}
</style>

View File

@@ -2,14 +2,16 @@
<div class="intersection_div"> <div class="intersection_div">
<div class="intersection_content test"> <div class="intersection_content test">
<h2 class="test">{{ props.text }}</h2> <h2 class="test">{{ props.text }}</h2>
<a :href="props.buttonLink"><div class="button intersection_button_div test"> <RouterLink :to="buttonLink"><div class="button intersection_button_div test">
<p>{{buttonText}}</p> <p>{{buttonText}}</p>
</div></a> </div></RouterLink>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { RouterLink } from 'vue-router';
const props = defineProps({ const props = defineProps({
text:{ text:{
type: String, type: String,

View File

@@ -2,6 +2,7 @@ import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue' import HomeView from '../views/HomeView.vue'
import BaseArticle from '@/views/BaseArticle.vue' import BaseArticle from '@/views/BaseArticle.vue'
import SkillsView from '@/views/SkillsView.vue' import SkillsView from '@/views/SkillsView.vue'
import ContactView from '@/views/ContactView.vue'
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
@@ -21,6 +22,11 @@ const router = createRouter({
name: 'skills', name: 'skills',
component: SkillsView component: SkillsView
}, },
{
path: '/contact',
name: 'contact',
component: ContactView
},
{ {
path: '/about', path: '/about',
name: 'about', name: 'about',

36
src/views/ContactView.vue Normal file
View File

@@ -0,0 +1,36 @@
<template>
<Header/>
<div id="contact_content">
<h1>{{ $t("contact.title") }}</h1>
<p>{{ $t("contact.subtitle") }}</p>
<!--<img :src="ContactSvg"/>-->
<emails/>
</div>
</template>
<script setup>
import Header from '@/components/header.vue';
import emails from '@/components/contact/emails.vue';
import ContactSvg from '@/assets/svg/contact.svg';
</script>
<style scoped>
#contact_content{
width: 80%;
margin: auto;
margin-top: 20px;
display: flex;
flex-direction: column;
/*justify-content: center;*/
align-items: center;
text-align: center;
min-height: 100vh;
}
#contact_content img{
width: 100%;
max-width: 600px;
}
</style>

View File

@@ -15,7 +15,7 @@
<welcome/> <welcome/>
<intersection :text="i18n.t('home.contactMe')" :button-text="i18n.t('home.contactButton')" button-link="#"/> <intersection :text="i18n.t('home.contactMe')" :button-text="i18n.t('home.contactButton')" button-link="contact"/>
<presentation/> <presentation/>