mirror of
https://github.com/ArthurDanjou/website-old.git
synced 2026-01-14 12:14:42 +01:00
Working and clean fucking guestbook
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
"dependencies": {
|
||||
"@nuxt/content": "^1.14.0",
|
||||
"@nuxtjs/axios": "^5.13.6",
|
||||
"@nuxtjs/composition-api": "0.26.0",
|
||||
"@nuxtjs/composition-api": "^0.26.0",
|
||||
"@nuxtjs/dotenv": "^1.4.1",
|
||||
"@nuxtjs/i18n": "^7.0.2",
|
||||
"@nuxtjs/proxy": "^2.1.0",
|
||||
@@ -23,8 +23,7 @@
|
||||
"core-js": "^3.16.1",
|
||||
"nuxt": "^2.15.8",
|
||||
"prism-themes": "^1.8.0",
|
||||
"sass": "^1.37.5",
|
||||
"windicss": "^3.1.7"
|
||||
"sass": "^1.37.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/types": "^2.15.8",
|
||||
|
||||
@@ -72,8 +72,6 @@ const robots = {
|
||||
|
||||
const redirect = [
|
||||
{ from: '/source', to: 'https://github.com/arthurdanjou/ares' },
|
||||
{ from: '/twitter', to: 'https://twitter.com/arthurdanj' },
|
||||
{ from: '/github', to: 'https://github.com/arthurdanjou/' },
|
||||
{ from: '/shelf', to: '/blog' },
|
||||
{ from: '/posts', to: '/blog' },
|
||||
{ from: '/resume', to: '/cv' }
|
||||
|
||||
@@ -2,8 +2,5 @@
|
||||
export default [
|
||||
{
|
||||
src: '~/plugins/i18n.ts'
|
||||
},
|
||||
{
|
||||
src: '~/plugins/main.ts',
|
||||
}
|
||||
]
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</h3>
|
||||
<div v-if="experiences" v-for="experience in experiences">
|
||||
<Experience
|
||||
:title="experience.title"
|
||||
:title="experience.title.code"
|
||||
:company="experience.company"
|
||||
:location="experience.location"
|
||||
:begin="experience.begin_date"
|
||||
@@ -22,16 +22,21 @@ import {Experience} from "~/types/types";
|
||||
export default defineComponent({
|
||||
name: "ExperiencesAbout",
|
||||
setup() {
|
||||
const {$content, $sentry} = useContext()
|
||||
const {$axios, $sentry, app} = useContext()
|
||||
|
||||
const experiences = useAsync(() => {
|
||||
return $content('experiences')
|
||||
.sortBy('end_date', 'desc')
|
||||
.fetch<Experience>()
|
||||
.catch((error) => {
|
||||
$sentry.captureEvent(error)
|
||||
})
|
||||
})
|
||||
const experiences = useAsync(async () => {
|
||||
const response = await $axios.get('/api/experiences', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.API_TOKEN}`
|
||||
}
|
||||
})
|
||||
if (response.status === 200) {
|
||||
return response.data.experiences
|
||||
} else {
|
||||
app.error({statusCode: 500})
|
||||
$sentry.captureEvent(response.data)
|
||||
}
|
||||
}, 'experiences')
|
||||
|
||||
return {
|
||||
experiences
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<footer class="footer w-full mt-20">
|
||||
<div class="p-8 pb-0">
|
||||
<div class="lg:flex justify-evenly">
|
||||
<div class="lg:flex justify-evenly items-center">
|
||||
<div class="lg:w-1/3">
|
||||
<div class="flex">
|
||||
<Logo />
|
||||
@@ -41,7 +41,8 @@
|
||||
<h1 class="font-bold mb-4 text-lg underline">
|
||||
{{ $t('footer.links') }}
|
||||
</h1>
|
||||
<div class="flex flex-col mb-8 space-y-2 lg:space-y-4 font-medium">
|
||||
<div class="flex flex-col lg:flex-row mb-8 font-medium">
|
||||
<div class="space-y-2 lg:space-y-4 mr-16">
|
||||
<div class="link">
|
||||
<nuxt-link to="/" :class="{'link-active': isWindow('')}">
|
||||
{{ $t('header.home') }}
|
||||
@@ -62,6 +63,8 @@
|
||||
{{ $t('header.projects') }}
|
||||
</nuxt-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-2 lg:space-y-4 ">
|
||||
<div class="link">
|
||||
<nuxt-link to="/services" :class="{'link-active': isWindow('services')}">
|
||||
{{ $t('header.services') }}
|
||||
@@ -72,11 +75,6 @@
|
||||
{{ $t('header.env') }}
|
||||
</nuxt-link>
|
||||
</div>
|
||||
<div class="link">
|
||||
<nuxt-link to="/guestbook" :class="{'link-active': isWindow('guestbook')}">
|
||||
{{ $t('header.guestbook') }}
|
||||
</nuxt-link>
|
||||
</div>
|
||||
<div class="link">
|
||||
<nuxt-link to="/newsletter" :class="{'link-active': isWindow('newsletter')}">
|
||||
{{ $t('header.newsletter') }}
|
||||
@@ -88,6 +86,7 @@
|
||||
</nuxt-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center border-t-2 border-gray-200 dark:border-gray-800 py-8 lg:flex lg:flex-row-reverse justify-between">
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
</h3>
|
||||
<div v-if="formations" v-for="formation in formations">
|
||||
<Formation
|
||||
:title="formation.title"
|
||||
:description="formation.description"
|
||||
:title="formation.title.code"
|
||||
:description="formation.description.code"
|
||||
:location="formation.location"
|
||||
:begin="formation.begin_date"
|
||||
:end="formation.end_date" />
|
||||
@@ -22,15 +22,20 @@ import {Formation} from "~/types/types";
|
||||
export default defineComponent({
|
||||
name: "FormationsHome",
|
||||
setup() {
|
||||
const {$content, $sentry} = useContext()
|
||||
const {$axios, $sentry, app} = useContext()
|
||||
|
||||
const formations = useAsync(() => {
|
||||
return $content('formations')
|
||||
.sortBy('end_date', 'desc')
|
||||
.fetch<Formation>()
|
||||
.catch((error) => {
|
||||
$sentry.captureEvent(error)
|
||||
})
|
||||
const formations = useAsync(async () => {
|
||||
const response = await $axios.get('/api/formations', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.API_TOKEN}`
|
||||
}
|
||||
})
|
||||
if (response.status === 200) {
|
||||
return response.data.formations
|
||||
} else {
|
||||
app.error({statusCode: 500})
|
||||
$sentry.captureEvent(response.data)
|
||||
}
|
||||
}, 'formations')
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
<template>
|
||||
<section class="p-6 border border-indigo-600 dark:border-indigo-700 rounded-lg text-justify">
|
||||
<h1 class="text-black font-bold dark:text-white text-2xl">{{ $t('guestbook.signin') }}</h1>
|
||||
<h3 class="text-gray-500 dark:text-gray-400">{{ $t('guestbook.share') }}</h3>
|
||||
<div v-if="!loginRef" class="flex space-x-4 my-3">
|
||||
<div @click="login('google')" class="icon-parent flex justify-center items-center p-2 border border-black dark:border-white duration-300 cursor-pointer">
|
||||
<GoogleIcon />
|
||||
</div>
|
||||
<div @click="login('github')" class="icon-parent flex justify-center items-center p-2 border border-black dark:border-white duration-300 cursor-pointer">
|
||||
<GithubIcon />
|
||||
</div>
|
||||
<div @click="login('twitter')" class="icon-parent flex justify-center items-center p-2 border border-black dark:border-white duration-300 cursor-pointer">
|
||||
<TwitterIcon />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="my-3">
|
||||
<form class="relative">
|
||||
<input
|
||||
required
|
||||
type="text"
|
||||
:placeholder="$t('guestbook.placeholder')"
|
||||
v-model="form.message"
|
||||
class="pl-4 pr-32 py-2 mt-1 block w-full border-gray-300 rounded-md bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"
|
||||
>
|
||||
<button
|
||||
@click.prevent="handleForm"
|
||||
v-if="form.message && form.message.length > 0"
|
||||
class="button flex items-center justify-center px-8 py-1 font-bold bg-gray-100 dark:bg-gray-700 hover:dark:bg-gray-800 text-gray-900 dark:text-gray-100 rounded hover:bg-gray-300 duration-300"
|
||||
>
|
||||
{{ $t('guestbook.sign') }}
|
||||
</button>
|
||||
</form>
|
||||
<div class="flex">
|
||||
<div v-if="error" class="py-1 text-red-400 text-sm">
|
||||
{{ $t('guestbook.error') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div v-if="success" class="py-1 text-green-400 text-sm">
|
||||
{{ $t('guestbook.success') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm text-gray-400 dark:text-gray-600">{{ $t('guestbook.infos') }}</p>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {defineComponent, ref, useContext} from "@nuxtjs/composition-api";
|
||||
import {GuestbookForm} from "~/types/types";
|
||||
|
||||
export default defineComponent({
|
||||
name: "GuestBookForm",
|
||||
setup() {
|
||||
const { $axios, $sentry, app } = useContext()
|
||||
|
||||
const loginRef = ref(false)
|
||||
const login = async (driver: 'github' | 'google' | 'twitter') => {
|
||||
const response = await $axios.get(`/api/auth/${driver}`, {
|
||||
headers: {
|
||||
'Accept': '*/*',
|
||||
}
|
||||
})
|
||||
if (response.status === 200) {
|
||||
loginRef.value = true
|
||||
await hasAlreadySignMessage(response.data.user.id)
|
||||
} else {
|
||||
$sentry.captureEvent(response.data)
|
||||
app.error({statusCode: 500})
|
||||
}
|
||||
}
|
||||
|
||||
const error = ref(false)
|
||||
const success = ref(false)
|
||||
const form = ref<GuestbookForm>({} as GuestbookForm)
|
||||
|
||||
const handleForm = async () => {
|
||||
const response = await $axios.post('/api/guestbook', {
|
||||
message: form.value.message,
|
||||
email: 'contact@arthurdanjou.fr'
|
||||
}, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.API_TOKEN}`
|
||||
}
|
||||
})
|
||||
if (response.status === 200) {
|
||||
form.value.message = ''
|
||||
success.value = true
|
||||
} else {
|
||||
$sentry.captureEvent(response.data)
|
||||
error.value = true
|
||||
setTimeout(() => {
|
||||
error.value = false
|
||||
}, 5000)
|
||||
}
|
||||
}
|
||||
|
||||
const alreadySent = ref(false)
|
||||
const hasAlreadySignMessage = async (id: number) => {
|
||||
const response = await $axios.get(`/api/guestbook/${id}`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.API_TOKEN}`
|
||||
}
|
||||
})
|
||||
if (response.status === 200) {
|
||||
switch (response.data.signed) {
|
||||
case 0:
|
||||
alreadySent.value = false
|
||||
break
|
||||
case 1:
|
||||
alreadySent.value = true
|
||||
break
|
||||
}
|
||||
} else {
|
||||
$sentry.captureEvent(response.data)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
login,
|
||||
form,
|
||||
success,
|
||||
error,
|
||||
alreadySent,
|
||||
loginRef,
|
||||
handleForm,
|
||||
hasAlreadySignMessage
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.icon-parent svg {
|
||||
@apply duration-300;
|
||||
}
|
||||
.icon-parent:hover svg {
|
||||
@apply transform scale-110;
|
||||
}
|
||||
.button {
|
||||
position: absolute;
|
||||
top: 0.25rem;
|
||||
right: 0.25rem;
|
||||
}
|
||||
</style>
|
||||
@@ -1,60 +0,0 @@
|
||||
<template>
|
||||
<div class="my-6">
|
||||
<div class="text-justify leading-6 text-black dark:text-white">
|
||||
{{ message }}
|
||||
</div>
|
||||
<div class="flex mt-3">
|
||||
<div class="text-gray-600 dark:text-gray-300">
|
||||
{{ author }}
|
||||
</div>
|
||||
<div class="text-gray-200 px-3 dark:text-gray-700">/</div>
|
||||
<div class="text-gray-400 dark:text-gray-500 lining-nums">
|
||||
{{ formatDateAndTime }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {computed, defineComponent, useContext} from "@nuxtjs/composition-api";
|
||||
|
||||
interface GuestBookMessageProps {
|
||||
author: string,
|
||||
message: string,
|
||||
date: string
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: "GuestbookMessage",
|
||||
props: {
|
||||
message: {
|
||||
type: String,
|
||||
default: 'Guestbook Message'
|
||||
},
|
||||
author: {
|
||||
type: String,
|
||||
default: "Guestbook Author"
|
||||
},
|
||||
date: {
|
||||
type: String,
|
||||
default: "Guestbook Date"
|
||||
}
|
||||
},
|
||||
setup(props: GuestBookMessageProps) {
|
||||
const {i18n} = useContext()
|
||||
|
||||
const formatDateAndTime = computed(() => {
|
||||
const date = new Date(props.date)
|
||||
const realMonth = date.getMonth()+1
|
||||
const month = realMonth.toString().length == 2 ? realMonth.toString() : `0${realMonth.toString()}`
|
||||
const minutes = date.getMinutes().toString().length == 2 ? date.getMinutes() : `0${date.getMinutes()}`
|
||||
const hours = date.getHours().toString().length == 2 ? date.getHours() : `0${date.getHours()}`
|
||||
return `${date.getDate()} ${i18n.t(`month.${month}`)} ${date.getFullYear()} ${i18n.t('guestbook.at')} ${hours}:${minutes}`
|
||||
})
|
||||
|
||||
return {
|
||||
formatDateAndTime
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -33,7 +33,7 @@ const PAGE_TYPE = {
|
||||
services: 2,
|
||||
env: 3,
|
||||
about: 4,
|
||||
guestbook: 5
|
||||
newsletter: 5
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
|
||||
@@ -65,11 +65,6 @@
|
||||
{{ $t('header.env') }}
|
||||
</nuxt-link>
|
||||
</div>
|
||||
<div class="nav-link" :class="{ 'link-active': isWindow('guestbook') }">
|
||||
<nuxt-link to="/guestbook">
|
||||
{{ $t('header.guestbook') }}
|
||||
</nuxt-link>
|
||||
</div>
|
||||
<div class="nav-link" :class="{ 'link-active': isWindow('newsletter') }">
|
||||
<nuxt-link to="/newsletter">
|
||||
{{ $t('header.newsletter') }}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
[
|
||||
{
|
||||
"slug": "erisium",
|
||||
"title": "experiences.erisium",
|
||||
"company": "Erisium",
|
||||
"location": "Remote",
|
||||
"begin_date": "02-2019",
|
||||
"end_date": "11-2020"
|
||||
},
|
||||
{
|
||||
"slug": "freelance",
|
||||
"title": "experiences.freelance",
|
||||
"company": "ArtDanjProduction",
|
||||
"location": "France",
|
||||
"begin_date": "09-2015",
|
||||
"end_date": "Today"
|
||||
},
|
||||
{
|
||||
"slug": "idemia",
|
||||
"title": "experiences.idemia",
|
||||
"company": "Idemia, Courbevoie",
|
||||
"location": "France",
|
||||
"begin_date": "06-2019",
|
||||
"end_date": "06-2019"
|
||||
},
|
||||
{
|
||||
"slug": "la-salle-a-manger",
|
||||
"title": "experiences.lsam",
|
||||
"company": "La Salle à manger, Boulogne Billancourt",
|
||||
"location": "France",
|
||||
"begin_date": "04-2018",
|
||||
"end_date": "04-2018"
|
||||
}
|
||||
]
|
||||
@@ -1,26 +0,0 @@
|
||||
[
|
||||
{
|
||||
"slug": "freelance",
|
||||
"title": "formations.freelance.title",
|
||||
"description": "formations.freelance.description",
|
||||
"location": "Remote",
|
||||
"begin_date": "04-2015",
|
||||
"end_date": "Today"
|
||||
},
|
||||
{
|
||||
"slug": "bac",
|
||||
"title": "formations.bac.title",
|
||||
"description": "formations.bac.description",
|
||||
"location": "France",
|
||||
"begin_date": "09-2020",
|
||||
"end_date": "07-2021 "
|
||||
},
|
||||
{
|
||||
"slug": "dnb",
|
||||
"title": "formations.dnb.title",
|
||||
"description": "formations.dnb.description",
|
||||
"location": "France",
|
||||
"begin_date": "09-2017",
|
||||
"end_date": "09-2018"
|
||||
}
|
||||
]
|
||||
@@ -8,7 +8,6 @@ const translations = {
|
||||
contact: 'Contact',
|
||||
projects: 'Projects',
|
||||
env: 'Tools',
|
||||
guestbook: 'Guestbook',
|
||||
newsletter: 'Newsletter',
|
||||
services: 'Services'
|
||||
},
|
||||
@@ -23,15 +22,36 @@ const translations = {
|
||||
projects: 'My projects',
|
||||
contact: 'Contact me',
|
||||
env: 'My environment',
|
||||
guestbook: 'My guestbook',
|
||||
newsletter: 'My newsletter'
|
||||
newsletter: 'My newsletter',
|
||||
services: 'My services'
|
||||
},
|
||||
|
||||
services: {
|
||||
description: 'Je fourni tout ce dont vous avez besoin pour créer votre site internet parfait',
|
||||
1: {
|
||||
title: "Développement d'application",
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam vulputate quam vel maximus pulvinar. Aliquam vitae risus at sem varius pulvinar. Vivamus pulvinar tortor sit amet condimentum aliquam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse finibus, metus eu dictum aliquet, tellus libero aliquam libero, eu lacinia dui mauris congue dolor. Nunc a lacinia ligula. Mauris bibendum orci eget pretium consequat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vivamus porttitor finibus odio.'
|
||||
},
|
||||
2: {
|
||||
title: "Installation d'infrastructure",
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam vulputate quam vel maximus pulvinar. Aliquam vitae risus at sem varius pulvinar. Vivamus pulvinar tortor sit amet condimentum aliquam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse finibus, metus eu dictum aliquet, tellus libero aliquam libero, eu lacinia dui mauris congue dolor. Nunc a lacinia ligula. Mauris bibendum orci eget pretium consequat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vivamus porttitor finibus odio.'
|
||||
},
|
||||
3: {
|
||||
title: "Conseil dans l'informatique",
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam vulputate quam vel maximus pulvinar. Aliquam vitae risus at sem varius pulvinar. Vivamus pulvinar tortor sit amet condimentum aliquam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse finibus, metus eu dictum aliquet, tellus libero aliquam libero, eu lacinia dui mauris congue dolor. Nunc a lacinia ligula. Mauris bibendum orci eget pretium consequat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vivamus porttitor finibus odio.'
|
||||
},
|
||||
4: {
|
||||
title: "Revue de vos applications",
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam vulputate quam vel maximus pulvinar. Aliquam vitae risus at sem varius pulvinar. Vivamus pulvinar tortor sit amet condimentum aliquam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse finibus, metus eu dictum aliquet, tellus libero aliquam libero, eu lacinia dui mauris congue dolor. Nunc a lacinia ligula. Mauris bibendum orci eget pretium consequat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vivamus porttitor finibus odio.'
|
||||
},
|
||||
},
|
||||
|
||||
footer: {
|
||||
credits: 'Developed and designed with ❤️ using',
|
||||
credits_separator: 'by',
|
||||
credits_separator_and: 'and',
|
||||
copyrights: '© Copyright {date} - All rights reserved'
|
||||
description: 'Développeur Web et Logiciel, mais également étudiant en Mathématiques et en Physique. Je développe des sites internet',
|
||||
links: 'Quick links',
|
||||
credits: 'Developed with',
|
||||
credits_separator: 'and',
|
||||
copyrights: '© {date} Arthur Danjou - All rights reserved'
|
||||
},
|
||||
|
||||
error: {
|
||||
@@ -54,13 +74,6 @@ const translations = {
|
||||
main: 'but also',
|
||||
strong: 'student'
|
||||
},
|
||||
contact: {
|
||||
follow: 'You can follow me on',
|
||||
and: 'and',
|
||||
spacer: 'or simply by',
|
||||
contact: 'Contacting',
|
||||
me: 'me.'
|
||||
},
|
||||
color: {
|
||||
develop: 'Develop.',
|
||||
publish: 'Publish.',
|
||||
@@ -102,6 +115,7 @@ const translations = {
|
||||
1: 'I am a young creative developer who loves to tinker and touch everything! I am very interested in new technologies, development and IT.',
|
||||
2: 'I love sharing my knowledge and helping others through lives on Twitchs, technical articles on my blog, open-source projects or by reviewing community code. As long as I share my passions, I will continue to do this.',
|
||||
3: 'I am able to quickly learn new technologies to meet the needs of different projects. I often identify the need for new systems or tools to improve workflow efficiency. I am always motivated by a challenge and like to be well organized to produce consistent results.',
|
||||
4: 'En parallèle du développement, je suis étudiant en Mathématiques et en Physique dans la faculté des Sciences Paris-Saclay. De plus, je suis un grand fan de moto.'
|
||||
},
|
||||
title: {
|
||||
skills: 'Skills',
|
||||
@@ -193,28 +207,9 @@ const translations = {
|
||||
why: {
|
||||
title: 'Why contact me ? 📩',
|
||||
description: "Please don't hesitate to contact me if you have any questions, think we could work together or if you just want to chat ✌️"
|
||||
},
|
||||
available: {
|
||||
title: 'Am I available? 🚩',
|
||||
description: 'This status will be updated in real time to let you know if I am available for projects.',
|
||||
start: 'I am currently',
|
||||
end: 'for projects'
|
||||
}
|
||||
},
|
||||
|
||||
guestbook: {
|
||||
description: "Leave a comment below. It can be anything and everything - an appreciation, a message, a joke, etc.",
|
||||
signin: "Sign the guestbook",
|
||||
share: 'Share a message to future visitors to this site.',
|
||||
login: 'Login',
|
||||
infos: 'Your information is only used to display your name and reply by email.',
|
||||
placeholder: 'Your message...',
|
||||
sign: 'Sign',
|
||||
error: 'Error while sending your message ❌',
|
||||
success: 'Thank you for your message 😉',
|
||||
at: 'at'
|
||||
},
|
||||
|
||||
newsletter: {
|
||||
description: 'My newsletter provides a behind-the-scenes look into what I\'m working on and writing about. I frequently share some of my favorite articles I\'ve read, as well as anything fascinating about technology.',
|
||||
title: 'Subscribe to my newsletter',
|
||||
@@ -250,46 +245,6 @@ const translations = {
|
||||
12: 'December',
|
||||
},
|
||||
|
||||
hiring: {
|
||||
status: {
|
||||
not_available: 'not available',
|
||||
available: 'available'
|
||||
}
|
||||
},
|
||||
|
||||
tags: {
|
||||
life: 'Life',
|
||||
dev: 'Dev',
|
||||
tech: 'Tech',
|
||||
software: 'Software',
|
||||
web: 'Web',
|
||||
api: 'API',
|
||||
mc: 'Minecraft',
|
||||
opensource: 'Open-Source'
|
||||
},
|
||||
|
||||
experiences: {
|
||||
erisium: 'Junior Developer',
|
||||
freelance: 'FullStack Software & Web Development',
|
||||
idemia: 'Discovery of the IT sector & the data-center',
|
||||
lsam: 'Room cleaning - Waiter - Taking orders - Welcoming customers'
|
||||
},
|
||||
|
||||
formations: {
|
||||
freelance: {
|
||||
title: 'Self-learning',
|
||||
description: 'Java, TypeScript, Go, etc...'
|
||||
},
|
||||
dnb: {
|
||||
title: 'Diplôme National du Brevet',
|
||||
description: 'Obtention du Brevet mention Très Bien'
|
||||
},
|
||||
bac: {
|
||||
title: 'Baccalauréat',
|
||||
description: 'General Baccalaureate Physics / Chemistry & Mathematics'
|
||||
}
|
||||
},
|
||||
|
||||
works: {
|
||||
athena: 'Athena is my personal API connected to my various instances',
|
||||
ares: 'Ares is my personal website creating a single point of contact',
|
||||
|
||||
@@ -8,7 +8,6 @@ const translations = {
|
||||
contact: 'Contact',
|
||||
projects: 'Projets',
|
||||
env: 'Outils',
|
||||
guestbook: "Livre d'or",
|
||||
newsletter: 'Newsletter',
|
||||
services: 'Services'
|
||||
},
|
||||
@@ -17,25 +16,36 @@ const translations = {
|
||||
close: 'Fermer le menu'
|
||||
},
|
||||
|
||||
services: {
|
||||
description: 'Je fourni tout ce dont vous avez besoin pour créer votre site internet parfait',
|
||||
1: {
|
||||
title: "Développement d'application",
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam vulputate quam vel maximus pulvinar. Aliquam vitae risus at sem varius pulvinar. Vivamus pulvinar tortor sit amet condimentum aliquam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse finibus, metus eu dictum aliquet, tellus libero aliquam libero, eu lacinia dui mauris congue dolor. Nunc a lacinia ligula. Mauris bibendum orci eget pretium consequat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vivamus porttitor finibus odio.'
|
||||
}
|
||||
},
|
||||
|
||||
part: {
|
||||
about: 'A propos',
|
||||
contact: 'Me contacter',
|
||||
projects: 'Mes projets',
|
||||
blog: 'Mon blog',
|
||||
env: 'Mon environnement',
|
||||
guestbook: "Mon livre d'or",
|
||||
newsletter: 'Ma newsletter',
|
||||
services: 'Mes services'
|
||||
},
|
||||
|
||||
services: {
|
||||
description: 'Je fourni tout ce dont vous avez besoin pour créer votre site internet parfait',
|
||||
1: {
|
||||
title: "Développement d'application",
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam vulputate quam vel maximus pulvinar. Aliquam vitae risus at sem varius pulvinar. Vivamus pulvinar tortor sit amet condimentum aliquam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse finibus, metus eu dictum aliquet, tellus libero aliquam libero, eu lacinia dui mauris congue dolor. Nunc a lacinia ligula. Mauris bibendum orci eget pretium consequat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vivamus porttitor finibus odio.'
|
||||
},
|
||||
2: {
|
||||
title: "Installation d'infrastructure",
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam vulputate quam vel maximus pulvinar. Aliquam vitae risus at sem varius pulvinar. Vivamus pulvinar tortor sit amet condimentum aliquam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse finibus, metus eu dictum aliquet, tellus libero aliquam libero, eu lacinia dui mauris congue dolor. Nunc a lacinia ligula. Mauris bibendum orci eget pretium consequat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vivamus porttitor finibus odio.'
|
||||
},
|
||||
3: {
|
||||
title: "Conseil dans l'informatique",
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam vulputate quam vel maximus pulvinar. Aliquam vitae risus at sem varius pulvinar. Vivamus pulvinar tortor sit amet condimentum aliquam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse finibus, metus eu dictum aliquet, tellus libero aliquam libero, eu lacinia dui mauris congue dolor. Nunc a lacinia ligula. Mauris bibendum orci eget pretium consequat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vivamus porttitor finibus odio.'
|
||||
},
|
||||
4: {
|
||||
title: "Revue de vos applications",
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam vulputate quam vel maximus pulvinar. Aliquam vitae risus at sem varius pulvinar. Vivamus pulvinar tortor sit amet condimentum aliquam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse finibus, metus eu dictum aliquet, tellus libero aliquam libero, eu lacinia dui mauris congue dolor. Nunc a lacinia ligula. Mauris bibendum orci eget pretium consequat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vivamus porttitor finibus odio.'
|
||||
},
|
||||
},
|
||||
|
||||
footer: {
|
||||
description: 'Développeur Web et Logiciel, mais également étudiant en Mathématiques et en Physique. Je développe des sites internet',
|
||||
links: 'Liens rapides',
|
||||
@@ -64,13 +74,6 @@ const translations = {
|
||||
main: 'Mais également',
|
||||
strong: 'étudiant'
|
||||
},
|
||||
contact: {
|
||||
follow: 'Vous pouvez me suivre sur',
|
||||
and: 'et',
|
||||
spacer: 'ou tout simplement en me',
|
||||
contact: 'Contactant',
|
||||
me: '.'
|
||||
},
|
||||
color: {
|
||||
develop: 'Développer.',
|
||||
publish: 'Publier.',
|
||||
@@ -204,30 +207,7 @@ const translations = {
|
||||
why: {
|
||||
title: 'Pourquoi me contacter ? 📩',
|
||||
description: "N'hésitez pas à me contacter si vous avez des questions, pensez que nous pourrions travailler ensemble ou si vous souhaitez simplement discuter ✌️"
|
||||
},
|
||||
available: {
|
||||
title: 'Suis-je disponible ? 🚩',
|
||||
description: 'Ce status sera mis à jour en temps réel pour vous indiquer si je suis disponible pour du travail.',
|
||||
start: 'Je suis actuellement',
|
||||
end: 'pour du travail'
|
||||
},
|
||||
services: {
|
||||
title: 'Voici la liste de services proposés 🛍'
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
guestbook: {
|
||||
description: "Laissez un commentaire ci-dessous. Cela peut être tout et n'importe quoi - une appréciation, un message, une blague, etc...",
|
||||
signin: "Signer le livre d'or",
|
||||
share: 'Partagez un message aux futurs visiteurs de ce site.',
|
||||
login: 'Connexion',
|
||||
infos: 'Vos informations ne sont utilisées que pour afficher votre nom et répondre par e-mail.',
|
||||
placeholder: 'Votre message...',
|
||||
sign: 'Signer',
|
||||
error: "Erreur lors de l'envoi de votre message ❌",
|
||||
success: 'Merci pour votre message 😉',
|
||||
at: 'à'
|
||||
},
|
||||
|
||||
newsletter: {
|
||||
@@ -265,46 +245,6 @@ const translations = {
|
||||
12: 'Décembre',
|
||||
},
|
||||
|
||||
hiring: {
|
||||
status: {
|
||||
not_available: 'non disponible',
|
||||
available: 'disponible'
|
||||
}
|
||||
},
|
||||
|
||||
tags: {
|
||||
life: 'Vie',
|
||||
dev: 'Dev',
|
||||
tech: 'Tech',
|
||||
software: 'Logiciel',
|
||||
web: 'Web',
|
||||
api: 'API',
|
||||
mc: 'Minecraft',
|
||||
opensource: 'Open-Source'
|
||||
},
|
||||
|
||||
experiences: {
|
||||
erisium: 'Développeur Junior',
|
||||
freelance: 'Développement FullStack Web & Logiciel',
|
||||
idemia: 'Découverte du secteur IT & du data-center',
|
||||
lsam: 'Nettoyage de la salle – Serveur – Prise de commandes – Accueil des clients'
|
||||
},
|
||||
|
||||
formations: {
|
||||
freelance: {
|
||||
title: 'Auto-apprentissage',
|
||||
description: 'Java, TypeScript, Go, etc...'
|
||||
},
|
||||
dnb: {
|
||||
title: 'Diplôme National du Brevet',
|
||||
description: 'Obtention du Brevet mention Très Bien'
|
||||
},
|
||||
bac: {
|
||||
title: 'Baccalauréat',
|
||||
description: 'Baccalauréat Général Physique/Chimie & Mathématiques'
|
||||
}
|
||||
},
|
||||
|
||||
works: {
|
||||
athena: 'Athena est mon API personnelle connectée à mes diverses instances.',
|
||||
ares: 'Ares est mon site personnel créant un point de contact unique.',
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
<template>
|
||||
<main v-if="guestbook_messages" class="flex flex-col mb-8 px-4 xl:px-64">
|
||||
<PageTitle class="self-center" title="part.guestbook"/>
|
||||
<section class="flex flex-col 2xl:flex-row items-center py-8">
|
||||
<div class="ml-2 text-lg leading-6 text-justify dark:text-gray-400 text-gray-700">
|
||||
<p>{{ $t('guestbook.description') }}</p>
|
||||
</div>
|
||||
</section>
|
||||
<GuestBookForm />
|
||||
<section class="flex flex-col py-8">
|
||||
<div v-for="message in guestbook_messages">
|
||||
<GuestbookMessage
|
||||
:message="message.message"
|
||||
:author="message.user.username"
|
||||
:date="message.created_at"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {defineComponent, useAsync, useContext} from "@nuxtjs/composition-api";
|
||||
import GuestbookMessage from "@/components/GuestbookMessage.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "guestbook",
|
||||
head() {
|
||||
return {
|
||||
title: `${this.$i18n.t('header.guestbook')} - Arthur Danjou`
|
||||
}
|
||||
},
|
||||
setup() {
|
||||
const { $axios, $sentry, app } = useContext()
|
||||
|
||||
const guestbook_messages = useAsync<typeof GuestbookMessage[]>(async () => {
|
||||
const response = await $axios.get('/api/guestbook', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.API_TOKEN}`
|
||||
}
|
||||
})
|
||||
if (response.status === 200) {
|
||||
return response.data.guestbook_messages
|
||||
} else {
|
||||
app.error({statusCode: 500})
|
||||
$sentry.captureEvent(response.data)
|
||||
}
|
||||
}, 'guestbook_messages')
|
||||
|
||||
return {
|
||||
guestbook_messages
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -4,19 +4,19 @@
|
||||
<p class="text-justify text-gray-700 dark:text-gray-400 text-xl my-8">{{ $t('services.description') }}</p>
|
||||
<div class="flex flex-col justify-around items-center py-10 w-full">
|
||||
<div class="flex flex-col lg:(flex-row justify-around mb-16) w-full">
|
||||
<ServicePart>
|
||||
<GlassIcon />
|
||||
<ServicePart title="services.1.title" content="services.1.content" >
|
||||
<CodeIcon />
|
||||
</ServicePart>
|
||||
<ServicePart>
|
||||
<ServicePart title="services.2.title" content="services.2.content">
|
||||
<NetworkIcon />
|
||||
</ServicePart>
|
||||
</div>
|
||||
<div class="flex flex-col lg:(flex-row justify-around) w-full">
|
||||
<ServicePart>
|
||||
<ServicePart title="services.3.title" content="services.3.content">
|
||||
<SupportIcon />
|
||||
</ServicePart>
|
||||
<ServicePart>
|
||||
<CodeIcon />
|
||||
<ServicePart title="services.4.title" content="services.4.content">
|
||||
<GlassIcon />
|
||||
</ServicePart>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,17 +2,20 @@ import {GetterTree, MutationTree} from "vuex";
|
||||
|
||||
export const state = () => ({
|
||||
opened: false,
|
||||
route: '/'
|
||||
route: '/',
|
||||
email: ''
|
||||
})
|
||||
|
||||
export type RootState = ReturnType<typeof state>
|
||||
|
||||
export const getters: GetterTree<RootState, RootState> = {
|
||||
opened: state => state.opened,
|
||||
route: state => state.route
|
||||
route: state => state.route,
|
||||
email: state => state.email
|
||||
}
|
||||
|
||||
export const mutations: MutationTree<RootState> = {
|
||||
TOGGLE_OPENED: (state, opened: boolean) => (state.opened = opened),
|
||||
SET_ROUTE: (state, route: string) => (state.route = route)
|
||||
SET_ROUTE: (state, route: string) => (state.route = route),
|
||||
SET_EMAIL: (state, email: string) => (state.email = email)
|
||||
}
|
||||
|
||||
@@ -61,10 +61,6 @@ interface Project {
|
||||
tags: Array<Tag>,
|
||||
}
|
||||
|
||||
interface GuestbookForm {
|
||||
message: string
|
||||
}
|
||||
|
||||
interface NewsletterForm {
|
||||
email: string
|
||||
}
|
||||
@@ -77,7 +73,8 @@ interface Translation {
|
||||
|
||||
interface State {
|
||||
opened: boolean,
|
||||
route: string
|
||||
route: string,
|
||||
email: string
|
||||
}
|
||||
|
||||
interface Announce {
|
||||
@@ -87,4 +84,4 @@ interface Announce {
|
||||
file: null
|
||||
}
|
||||
|
||||
export { Form, InfoData, Skill, Experience, Formation, Post, Tag, Project, GuestbookForm, NewsletterForm, Translation, State, Announce }
|
||||
export { Form, InfoData, Skill, Experience, Formation, Post, Tag, Project, NewsletterForm, Translation, State, Announce }
|
||||
|
||||
@@ -1414,7 +1414,7 @@
|
||||
defu "^5.0.0"
|
||||
lodash.template "^4.5.0"
|
||||
|
||||
"@nuxtjs/composition-api@0.26.0":
|
||||
"@nuxtjs/composition-api@^0.26.0":
|
||||
version "0.26.0"
|
||||
resolved "https://registry.yarnpkg.com/@nuxtjs/composition-api/-/composition-api-0.26.0.tgz#0fbda4fc942ca1e346b7c6d55a1fb331ff931a2a"
|
||||
integrity sha512-+4L9YDEN5h/vBY6xbBKPMIhgxbPv7psE4IVgKlF+QIekou6oN8m0T+QR2JLE0dHKwzicUbZLCr1v2Qw5T7L48A==
|
||||
|
||||
Reference in New Issue
Block a user