Merge branch 'dev'

# Conflicts:
#	package.json
#	yarn.lock
This commit is contained in:
2021-04-16 23:37:00 +02:00
143 changed files with 3946 additions and 3549 deletions

View File

@@ -1,37 +0,0 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Node.js CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
deploy_build_run:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node_version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node_version }}
- name: Deploy with SSH
uses: appleboy/ssh-action@v0.1.4
with:
host: ${{ secrets.SSH_HOST }}
port: ${{ secrets.SSH_PORT }}
username: ${{ secrets.SSH_USER }}
password: ${{ secrets.SSH_PASSPHRASE }}
script: |
cd ${{ secrets.PATH }}
git pull
yarn install
yarn build
pm2 start

13
.gitignore vendored
View File

@@ -41,9 +41,6 @@ jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
@@ -71,6 +68,9 @@ typings/
# nuxt.js build output
.nuxt
# Nuxt generate
dist
# vuepress build output
.vuepress/dist
@@ -88,10 +88,5 @@ sw.*
# Vim swap files
*.swp
/build/
/dist/
# Local Netlify folder
.netlify
/pages/blog/preview/
build

35
@types/index.d.ts vendored Normal file
View File

@@ -0,0 +1,35 @@
import { NuxtAxiosInstance } from '@nuxtjs/axios'
import VueI18n, {IVueI18n} from "vue-i18n";
import {ColorModeInstance} from "@nuxtjs/color-mode/types/color-mode";
import {NuxtApp} from "@nuxt/types/app";
import {NuxtStorage} from "@nuxtjs/universal-storage";
declare module 'vue/types/vue' {
interface Vue {
$axios: NuxtAxiosInstance,
i18n: VueI18n & IVueI18n
}
}
declare module '@nuxt/types' {
interface NuxtAppOptions {
$axios: NuxtAxiosInstance,
i18n: VueI18n & IVueI18n
}
interface Context {
$axios: NuxtAxiosInstance,
i18n: VueI18n & IVueI18n
$colorMode: ColorModeInstance,
$app: NuxtApp,
$storage: NuxtStorage
}
}
declare module 'vuex/types/index' {
interface Store<S> {
$axios: NuxtAxiosInstance,
i18n: VueI18n & IVueI18n
}
}

65
@types/types.ts Normal file
View File

@@ -0,0 +1,65 @@
interface Form {
email: string,
name: string,
content: string,
subject: string
}
interface InfoData {
age: number
hiring: {
status: string,
color: string
}
}
interface Skill {
title: string,
color: string,
cover: string,
slug: string
}
interface Experience {
slug: string,
title: string,
company: string,
location: string,
begin_date: string,
end_date: string
}
interface Formation {
slug: string,
title: string,
description: string,
location: string,
begin_date: string,
end_date: string
}
interface Tag {
slug: string
}
interface Post {
slug: string,
title: string,
description: string,
reading_time: number,
tags: Array<Tag>,
cover: string,
date: string
}
interface Project {
slug: string,
title: string,
description: string,
url: string,
cover: string,
color: string,
skills: Array<Skill>
}
export { Form, InfoData, Skill, Experience, Formation, Post, Tag, Project }

View File

@@ -1,6 +1,6 @@
MIT License
Copyright 2020 © Arthur Danjou
Copyright 2021 © Arthur Danjou
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -25,8 +25,8 @@ Hosted version : [arthurdanjou.fr](https://arthurdanjou.fr)
## Author 👤
➡ Arthur Danjou : Developer
- Twitter : [@ArthurDanj](https://twitter.com/ArthurDanj)
- GitHub : [@ArthurDanjou](https://github.com/ArthurDanjou)
- Twitter : [@ArthurDanj](https://twitter.com/ArthurDanj)
- GitHub : [@ArthurDanjou](https://github.com/ArthurDanjou)
## License 📑
Copyright © 2020 - [@ArthurDanj](https://arthurdanjou.fr) \

View File

@@ -1,20 +0,0 @@
.icon {
transform: translate(3px, -3px);
z-index: 1;
}
img, svg {
position: static;
}
body {
@apply dark:bg-dark-900
}
* {
@apply select-none outline-none;
}
.nuxt-content-editor {
@apply dark:bg-dark-800 border dark:border-white border-black border-solid;
}

View File

@@ -1,6 +0,0 @@
@import url('https://fonts.googleapis.com/css2?family=Raleway&display=swap');
@import "./style.scss";
@tailwind base;
@tailwind components;
@tailwind utilities;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>AdonisJS icon</title><path d="M13.333 1.333l-.596 1.193-2.404 4.807L8 2.667l-8 16h4.667l-2 4H24zm0 2.982l8.51 17.018H4.823l1.334-2.666H16l-4.922-9.843Z"/></svg>

Before

Width:  |  Height:  |  Size: 228 B

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.2" baseProfile="tiny" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" viewBox="0 0 2350 2314.8" xml:space="preserve">
<path d="M1175,0C525.8,0,0,525.8,0,1175c0,552.2,378.9,1010.5,890.1,1139.7c-5.9-14.7-8.8-35.3-8.8-55.8v-199.8H734.4
c-79.3,0-152.8-35.2-185.1-99.9c-38.2-70.5-44.1-179.2-141-246.8c-29.4-23.5-5.9-47,26.4-44.1c61.7,17.6,111.6,58.8,158.6,120.4
c47,61.7,67.6,76.4,155.7,76.4c41.1,0,105.7-2.9,164.5-11.8c32.3-82.3,88.1-155.7,155.7-190.9c-393.6-47-581.6-240.9-581.6-505.3
c0-114.6,49.9-223.3,132.2-317.3c-26.4-91.1-61.7-279.1,11.8-352.5c176.3,0,282,114.6,308.4,143.9c88.1-29.4,185.1-47,284.9-47
c102.8,0,196.8,17.6,284.9,47c26.4-29.4,132.2-143.9,308.4-143.9c70.5,70.5,38.2,261.4,8.8,352.5c82.3,91.1,129.3,202.7,129.3,317.3
c0,264.4-185.1,458.3-575.7,499.4c108.7,55.8,185.1,214.4,185.1,331.9V2256c0,8.8-2.9,17.6-2.9,26.4
C2021,2123.8,2350,1689.1,2350,1175C2350,525.8,1824.2,0,1175,0L1175,0z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,56 +0,0 @@
<template>
<div class="flex flex-row mb-5">
<div class="self-center flex h-4 w-4 mr-4 relative">
<span v-if="end === 'Today'" class="animate-ping relative inline h-4 w-4 rounded-full bg-orange-400 opacity-75"></span>
<span v-else class="inline relative h-4 w-4 rounded-full bg-gray-400 opacity-75"></span>
<span v-if="end === 'Today'" class="inline absolute rounded-full h-4 w-4 bg-orange-500"></span>
<span v-else class="inline absolute rounded-full h-4 w-4 bg-gray-500"></span>
</div>
<div class="leading-7">
<p v-if="isSameDate()" class="text-base dark:text-dark-100 text-gray-800 leading-6">{{ formatDate(begin) }} <span class="px-3">|</span> {{location}}</p>
<p v-else class="text-base dark:text-dark-100 text-gray-800 leading-6">{{ formatDate(begin) }} - {{ formatDate(end) }} <span class="px-3">|</span> {{location}}</p>
<h1 class="text-2xl font-bold">{{ $t(title) }}</h1>
<h2 class="text-xl">{{ company }}</h2>
</div>
</div>
</template>
<script>
export default {
name: "Experience",
props: {
title: {
type: String,
default: "Title"
},
company: {
type: String,
default: "ArtDanjProduction"
},
location: {
type: String,
default: "France"
},
begin: {
type: String,
default: "Now"
},
end: {
type: String,
default: "Never"
}
},
methods: {
formatDate(date) {
const dateFormat = date.split('-')
return date === 'Today' ? this.$t('date.today') : this.$t('month.' + dateFormat[0]) + " " + dateFormat[1]
},
isSameDate() {
return this.begin === this.end
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -1,53 +0,0 @@
<template>
<div class="flex flex-row mb-5">
<div class="self-center flex h-4 w-4 mr-4 relative">
<span v-if="end === 'Today'" class="animate-ping relative inline h-4 w-4 rounded-full bg-orange-400 opacity-75"></span>
<span v-else class="inline relative h-4 w-4 rounded-full bg-gray-400 opacity-75"></span>
<span v-if="end === 'Today'" class="inline absolute rounded-full h-4 w-4 bg-orange-500"></span>
<span v-else class="inline absolute rounded-full h-4 w-4 bg-gray-500"></span>
</div>
<div class="leading-7">
<p class="text-base dark:text-dark-100 text-gray-800 leading-6">{{ formatDate(begin) }} - {{ formatDate(end) }} <span class="px-3">|</span> {{location}}</p>
<h1 class="text-2xl font-bold">{{ $t(title) }}</h1>
<h2 class="text-xl">{{ $t(description) }}</h2>
</div>
</div>
</template>
<script>
export default {
name: "Formation",
props: {
title: {
type: String,
default: "Title"
},
description: {
type: String,
default: "Description"
},
location: {
type: String,
default: "Location"
},
begin: {
type: String,
default: "Now"
},
end: {
type: String,
default: "Never"
}
},
methods: {
formatDate(date) {
const dateFormat = date.split('-')
return date === 'Today' ? this.$t('date.today') : this.$t('month.' + dateFormat[0]) + " " + dateFormat[1]
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,175 +0,0 @@
<template>
<header class="dark:bg-dark-900 dark:text-white fixed z-50 top-0 left-0 bg-white header tracking-wider w-full h-16 lg:h-24 duration-500" :class="scrollPosition > 50 ? ' shadow-md dark:shadow-white' : ''">
<div class="header-container z-index-50 flex justify-between items-center h-full px-5 xl:px-64">
<nuxt-link to="/">
<div class="left text-2xl font-bold cursor-pointer border-b-2 border-opacity-0 dark:border-opacity-0 dark:hover:border-opacity-100 hover:border-opacity-100 border-black dark:border-white border-solid duration-500">
{{ $t('header.title') }}
</div>
</nuxt-link>
<nav class="right">
<div class="flex flex-col md:flex-row items-center">
<ul class="flex text-xl">
<li class="mx-2 cursor-pointer">
<div v-if="this.$i18n.locale === 'en'" @click="changeLanguage('fr')">
🇫🇷
</div>
<div v-else @click="changeLanguage('en')">
🇬🇧
</div>
</li>
<li @click="changeColorMode()" class="mx-2 cursor-pointer flex items-center">
<div v-if="this.$colorMode.value === 'light'">
<svg height="25" width="25" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
</svg>
</div>
<div v-else>
<svg height="25" width="25" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>
</div>
</li>
<nuxt-link class="red hidden md:inline-block" to="/">
<li class="hover:text-red-400 font-bold mx-2 cursor-pointer duration-300">
{{ $t('header.home') }}
</li>
</nuxt-link>
<nuxt-link class="orange hidden md:inline-block" to="/about">
<li class="hover:text-orange-400 font-bold mx-2 cursor-pointer duration-300">
{{ $t('header.about') }}
</li>
</nuxt-link>
<nuxt-link class="green hidden md:inline-block" to="/blog">
<li class="hover:text-green-400 font-bold mx-2 cursor-pointer duration-300">
{{ $t('header.blog') }}
</li>
</nuxt-link>
<nuxt-link class="blue hidden md:inline-block" to="/work">
<li class="hover:text-blue-400 font-bold mx-2 cursor-pointer duration-300">
{{ $t('header.work') }}
</li>
</nuxt-link>
<nuxt-link class="purple hidden md:inline-block" to="/contact">
<li class="hover:text-purple-400 font-bold mx-2 cursor-pointer duration-300">
{{ $t('header.contact') }}
</li>
</nuxt-link>
</ul>
</div>
<ul class="dark:text-white dark:bg-dark-900 text-sm z-50 bg-white md:hidden fixed bottom-0 left-0 w-full flex items-center justify-around h-20 border-t border-gray-200 border-solid navbar-bottom-items">
<nuxt-link to="/" class="w-1/5 red">
<li class="font-bold flex flex-col items-center justify-center">
<svg class="inline-block" height="20" width="20" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
</svg>
{{ $t('header.home') }}
</li>
</nuxt-link>
<nuxt-link to="/about" class="w-1/5 orange">
<li class="font-bold flex flex-col items-center justify-center">
<svg class="inline-block" height="20" width="20" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
{{ $t('header.about') }}
</li>
</nuxt-link>
<nuxt-link to="/blog" class="w-1/5 green">
<li class="font-bold flex flex-col items-center justify-center">
<svg class="inline-block" height="20" width="20" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
</svg>
{{ $t('header.blog') }}
</li>
</nuxt-link>
<nuxt-link to="/work" class="w-1/5 blue">
<li class="font-bold flex flex-col items-center justify-center">
<svg class="inline-block" height="20" width="20" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 13.255A23.931 23.931 0 0112 15c-3.183 0-6.22-.62-9-1.745M16 6V4a2 2 0 00-2-2h-4a2 2 0 00-2 2v2m4 6h.01M5 20h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
{{ $t('header.work') }}
</li>
</nuxt-link>
<nuxt-link to="/contact" class="w-1/5 purple">
<li class="font-bold flex flex-col items-center justify-center">
<svg class="inline-block" height="20" width="20" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
{{ $t('header.contact') }}
</li>
</nuxt-link>
</ul>
</nav>
</div>
</header>
</template>
<script>
export default {
name: "Header",
data () {
return {
scrollPosition: null
}
},
methods: {
changeColorMode() {
this.$colorMode.preference = this.$colorMode.value === 'light' ? 'dark' : 'light'
},
updateScroll() {
this.scrollPosition = window.scrollY
},
async changeLanguage(lang) {
await this.$i18n.setLocale(lang)
if (this.$router.currentRoute.fullPath.includes('blog')) {
await this.$nuxt.refresh()
}
},
},
mounted() {
window.addEventListener('scroll', this.updateScroll);
},
destroy() {
window.removeEventListener('scroll', this.updateScroll)
}
}
</script>
<style scoped lang="scss">
.header {
.header-container {
.nuxt-link-active {
&.green {
@apply text-green-400;
}
&.blue {
@apply text-blue-400;
}
}
.nuxt-link-exact-active {
&.red {
@apply text-red-400;
}
&.orange {
@apply text-orange-400;
}
&.green {
@apply text-green-400;
}
&.blue {
@apply text-blue-400;
}
&.purple {
@apply text-purple-400;
}
}
.navbar-bottom-items li {
transition: all .2s ease-in-out;
}
}
}
</style>

View File

@@ -1,70 +0,0 @@
<template>
<nuxt-link :to="link">
<div
class="mb-8 md:mb-0 home-link h-full duration-500 cursor-pointer flex flex-row justify-between py-3 w-full md:w-96 items-center"
:class="getColor"
>
<div class="ml-4">
<h1 class="text-2xl md:text-3xl font-bold my-2">
{{ $t(title) }}
<slot />
</h1>
<p class="w-5/6 text-gray-900 dark:text-dark-100 text-justify duration-300">{{ $t(description) }}</p>
</div>
<div class="mr-10 arrow duration-300">
<svg class="inline icon" height="25" width="25" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
</svg>
</div>
</div>
</nuxt-link>
</template>
<script>
export default {
name: "HomeLink",
props: {
title: {
default: "Title",
type: String
},
description: {
default: "Description",
type: String
},
color: {
default: "red-100",
type: String
},
link: {
default: "/",
type: String
}
},
computed: {
getColor() {
switch (this.color) {
case 'orange':
return 'hover:bg-orange-400 dark:hover:bg-orange-600 active:bg-orange-400 dark:active:bg-orange-600'
case 'purple':
return 'hover:bg-purple-400 dark:hover:bg-purple-600 active:bg-purple-400 dark:active:bg-purple-600'
case 'blue':
return 'hover:bg-blue-400 dark:hover:bg-blue-600 active:bg-blue-400 dark:active:bg-blue-600'
case 'green':
return 'hover:bg-green-400 dark:hover:bg-green-600 active:bg-green-400 dark:active:bg-green-600'
}
}
}
}
</script>
<style scoped lang="scss">
.home-link:hover {
p {
@apply dark:text-white
}
.arrow {
transform: translateX(15px);
}
}
</style>

View File

@@ -1,43 +0,0 @@
<template>
<h1
class="mt-16 md:mt-32 font-bold text-2xl md:text-4xl mr-2 inline mb-4 border-b-2 border-solid"
:class="getColor"
>
{{ $t(title) }}
<slot />
</h1>
</template>
<script>
export default {
name: "PageTitle",
props: {
title: {
default: 'Title',
type: String
},
color: {
default: 'red',
type: String
}
},
computed: {
getColor() {
switch (this.color) {
case 'orange':
return 'border-orange-400'
case 'purple':
return 'border-purple-400'
case 'blue':
return 'border-blue-400'
case 'green':
return 'border-green-400'
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,88 +0,0 @@
<template>
<article
class="post border-2 border-black border-solid rounded-xl w-full h-blog p-2 flex flex-col justify-between my-5 duration-200 transform hover:scale-95"
:style="{ backgroundImage: `url(${this.getBackgroundUrl})` }"
>
<div>
<p
class="text-2xl md:text-3xl font-bold md:text-justify leading-7 mb-3"
:class="lightBg ? 'text-black':'text-white'"
>{{ title }}</p>
<p
class="text-lg italic text-justify leading-5"
:class="lightBg ? 'text-gray-900':'text-dark-100'"
>{{ description }}</p>
</div>
<div
class="flex justify-between mt-8 items-end"
:class="lightBg ? 'text-gray-900':'text-dark-100'"
>
<div>
<div>{{formatDate}}</div>
<div>{{reading_time}} min</div>
</div>
<div class="self-end flex flex-wrap flex-col md:flex-row">
<div v-for="tag in tags"
class="my-1 md:my-0 ml-2 py-1 px-2 rounded font-semibold"
:class="lightBg ? 'bg-black text-white':'bg-white text-black'"
>
#{{ $t(tag) }}
</div>
</div>
</div>
</article>
</template>
<script>
export default {
name: "Post",
props: {
title: {
type: String,
default: "New Post's title "
},
description: {
type: String,
default: "New Post's description"
},
reading_time: {
type: Number,
default: 0
},
date: {
type: String,
default: "Today"
},
tags: {
type: Array,
default: () => ["Tag1", "Tag2", "Tag3"],
},
cover: {
type: String,
default: "default.png"
},
lightBg: {
type: Boolean,
default: false
}
},
computed: {
formatDate() {
const dateFormat = this.date.split('-')
return dateFormat[0] + " " + this.$t('month.' + dateFormat[1]) + " " + dateFormat[2]
},
getBackgroundUrl() {
return require(`~/assets/img/posts/${this.cover}.png`)
}
}
}
</script>
<style scoped lang="scss">
.h-blog {
min-height: 20rem;
background-position: center;
background-size: cover;
@apply bg-opacity-50;
}
</style>

View File

@@ -1,97 +0,0 @@
<template>
<div class="mb-3 mr-3 p-1 md:p-2 h-64 w-64 border-gray-900 dark:border-dark-200 border-2 duration-300 rounded-3xl hover:bg-opacity-25 hover:scale-105 transform cursor-pointer"
:class="getColor">
<div class="w-full h-full flex flex-col justify-center items-center">
<div class="text-center">
<img alt="Project Img" class="rounded-md" width="150" :src="require(`@/assets/img/works/${cover}.png`)">
</div>
<div class="text-center">
<h1 class="md:text-2xl text-lg font-bold">{{ title }}</h1>
<a :href="url" :class="'text-' + color + '-500'">{{ formatLink }}</a>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Work",
props: {
title: {
type: String,
default: 'Title'
},
url: {
type: String,
default: 'https://arthurdanjou.fr'
},
cover: {
type: String,
default: 'default.png'
},
color: {
type: String,
default: 'white'
}
},
computed: {
formatLink() {
return this.url.replace('https://', '').replace('http://', '')
},
getColor() {
switch (this.color) {
case 'orange':
return 'hover:bg-orange-600'
case 'purple':
return 'hover:bg-purple-600'
case 'blue':
return 'hover:bg-blue-600'
case 'green':
return 'hover:bg-green-600'
case 'yellow':
return 'hover:bg-yellow-600'
case 'cyan':
return 'hover:bg-cyan-600'
case 'teal':
return 'hover:bg-teal-600'
case 'amber':
return 'hover:bg-amber-600'
case 'blueGray':
return 'hover:bg-blueGray-600'
case 'emerald':
return 'hover:bg-emerald-600'
case 'lightBlue':
return 'hover:bg-lightBlue-600'
case 'lime':
return 'hover:bg-lime-600'
case 'rose':
return 'hover:bg-rose-600'
case 'black':
return 'hover:bg-black'
case 'white':
return 'hover:bg-white'
case 'pink':
return 'hover:bg-pink-600'
case 'fuchsia':
return 'hover:bg-fuchsia-600'
case 'violet':
return 'hover:bg-violet-600'
case 'indigo':
return 'hover:bg-indigo-600'
case 'warmGray':
return 'hover:bg-warmGray-600'
case 'trueGray':
return 'hover:bg-trueGray-600'
case 'gray':
return 'hover:bg-gray-600'
case 'coolGray':
return 'hover:bg-coolGray-600'
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,91 +0,0 @@
<template>
<div
class="m-2 p-1 md:p-2 h-48 w-48 border-gray-900 dark:border-dark-200 border-2 duration-300 rounded-3xl hover:bg-opacity-25"
:class="getColor"
>
<div class="w-full h-full flex flex-col justify-center items-center">
<div>
<img class="rounded-sm" alt="Skill Img" :src="require(`@/assets/img/skills/${cover}.png`)">
</div>
<h1 class="md:text-xl text-lg font-bold text-center">{{ skill }}</h1>
</div>
</div>
</template>
<script>
export default {
name: "WorkSkill",
props: {
skill: {
type: String,
default: "Rien"
},
color: {
type: String,
default: "red-100"
},
cover: {
type: String,
default: "logo.jpg"
}
},
computed: {
getColor() {
switch (this.color) {
case 'red':
return 'hover:bg-red-600'
case 'orange':
return 'hover:bg-orange-600'
case 'purple':
return 'hover:bg-purple-600'
case 'blue':
return 'hover:bg-blue-600'
case 'green':
return 'hover:bg-green-600'
case 'yellow':
return 'hover:bg-yellow-600'
case 'cyan':
return 'hover:bg-cyan-600'
case 'teal':
return 'hover:bg-teal-600'
case 'amber':
return 'hover:bg-amber-600'
case 'blueGray':
return 'hover:bg-blueGray-600'
case 'emerald':
return 'hover:bg-emerald-600'
case 'lightBlue':
return 'hover:bg-lightBlue-600'
case 'lime':
return 'hover:bg-lime-600'
case 'rose':
return 'hover:bg-rose-600'
case 'black':
return 'hover:bg-black'
case 'white':
return 'hover:bg-white'
case 'pink':
return 'hover:bg-pink-600'
case 'fuchsia':
return 'hover:bg-fuchsia-600'
case 'violet':
return 'hover:bg-violet-600'
case 'indigo':
return 'hover:bg-indigo-600'
case 'warmGray':
return 'hover:bg-warmGray-600'
case 'trueGray':
return 'hover:bg-trueGray-600'
case 'gray':
return 'hover:bg-gray-600'
case 'coolGray':
return 'hover:bg-coolGray-600'
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,4 +0,0 @@
export default {
credentials: true,
baseURL: 'https://api.arthurdanjou.fr/'
}

View File

@@ -1,6 +0,0 @@
export default {
preference: 'system',
fallback: 'light',
classPrefix: '',
classSuffix: '',
}

View File

@@ -1,16 +0,0 @@
export default {
apiPrefix: 'api',
nestedProperties: ['categories.slug'],
markdown: {
prism: {
theme: 'prism-themes/themes/prism-darcula.css'
},
remarkPlugins: [
'remark-squeeze-paragraphs',
'remark-slug',
'remark-autolink-headings',
'remark-external-links',
'remark-footnotes',
],
}
}

View File

@@ -1,18 +0,0 @@
export default {
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: 'ArtSite is my personal website build using NuxtJs to create a single point of contact' },
{ hid: 'og:type', name: 'og:type', content: 'website' },
{ hid: 'og:url', name: 'og:url', content: 'https://arthurdanjou.fr' },
{ hid: 'og:title', name: 'og:title', content: 'Arthur Danjou | FullStack Web & Software Developer' },
{ hid: 'og:site_name', name: 'og:site_name', content: 'Arthur Danjou | FullStack Web & Software Developer' },
{ hid: 'og:locale', name: 'og:locale', content: 'fr' },
{ hid: 'og:locale', name: 'og:locale', content: 'en' },
{ hid: 'og:image', name: 'og:image', content: '/images/image.jpg' },
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
}

View File

@@ -1,8 +0,0 @@
export default [
{ from: '/source', to: 'https://github.com/arthurdanjou/artsite' },
{ 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' },
]

View File

@@ -1,5 +0,0 @@
export default {
UserAgent: '*',
Sitemap: 'https://arthurdanjou.fr/sitemap.xml',
Allow: '*'
}

View File

@@ -1,7 +0,0 @@
export default {
path: '/sitemap.xml',
hostname: 'https://arthurdanjou.fr',
cacheTime: 720000,
gzip: true,
generate: false,
}

View File

@@ -1,5 +0,0 @@
export default {
cssPath: './assets/css/tailwind.css',
configPath: 'tailwind.config.js',
exposeConfig: true
}

View File

@@ -1,24 +0,0 @@
export default {
locales: [
{
code: 'en',
name: 'English',
iso: 'en-Us',
file: 'en-US.ts',
},
{
code: 'fr',
iso: 'fr-FR',
file: 'fr-FR.ts',
name: 'Français'
},
],
strategy: 'no_prefix',
defaultLocale: 'en',
langDir: 'locales/',
lazy: true,
seo: true,
vueI18n: {
fallbackLocale: 'en',
},
}

View File

@@ -1,11 +0,0 @@
import Axios from './Axios'
import Head from './Head'
import ColorMode from './ColorMode'
import Tailwind from './Tailwind'
import Translation from './Translation'
import Content from './Content'
import Robots from './Robots'
import SiteMap from "./SiteMap";
import Redirect from "./Redirect";
export { Axios, Head, ColorMode, Tailwind, Translation, Content, Robots, SiteMap, Redirect }

View File

@@ -1,67 +0,0 @@
[
{
"slug": "erisium",
"title": "Erisium",
"description": "works.erisium",
"url": "https://erisium.com",
"cover": "erisium",
"color": "fuchsia",
"skills": [
"java",
"git",
"redis",
"mariadb"
]
},
{
"slug": "artsite",
"title": "ArtSite",
"description": "works.artsite",
"url": "https://arthurdanjou.fr",
"cover": "artsite",
"color": "trueGray",
"skills": [
"typescript",
"nuxtjs",
"vuejs",
"git",
"tailwindcss",
"sass",
"html",
"css",
"nodejs"
]
},
{
"slug": "artapi",
"title": "ArtApi",
"description": "works.artapi",
"url": "https://api.arthurdanjou.fr",
"cover": "artapi",
"color": "trueGray",
"skills": [
"typescript",
"adonisjs",
"git",
"docker",
"nodejs",
"redis",
"mariadb"
]
},
{
"slug": "artclick",
"title": "ArtClick",
"description": "works.artclick",
"url": "https://artdanj.to",
"cover": "artclick",
"color": "trueGray",
"skills": [
"adonisjs",
"git",
"redis",
"mariadb",
"typescript"
]
}
]

View File

@@ -19,7 +19,7 @@ services:
- traefik.docker.network=proxy
- traefik.port=443
ports:
- 3333:3333
- 3333:3333
networks:
- internal
- proxy
@@ -53,27 +53,18 @@ services:
- internal
- proxy
labels:
- traefik.tcp.routers.sql.entrypoints=sql
- traefik.tcp.routers.sql.rule=HostSNI(`sql.arthurdanjou.fr`)
- traefik.tcp.routers.sql.tls=true
- traefik.tcp.routers.sql.tls.certresolver=lets-encrypt
- traefik.docker.network=proxy
- traefik.port=3306
volumes:
- "/root/mariadb/data:/var/lib/mysql"
redis:
image: redis:6.0.10
image: redis:latest
container_name: redis
command: redis-server --requirepass ${REDIS_PASSWORD}
command: redis-server
ports:
- 6379:6379
networks:
- internal
- proxy
labels:
- traefik.tcp.routers.redis.rule=HostSNI(`redis.arthurdanjou.fr`)
- traefik.tcp.routers.redis.tls=true
- traefik.tcp.routers.redis.tls.certresolver=lets-encrypt
- traefik.docker.network=proxy
- traefik.port=6379
volumes:
- "/root/redis/data:/data"

View File

@@ -1,18 +0,0 @@
<template>
<div class="dark:bg-dark-900 dark:text-white font-sans">
<Header />
<Nuxt class="z-10 pt-16 lg:pt-24 content" />
<Footer />
</div>
</template>
<script>
import Header from "~/components/Header";
import Footer from "~/components/Footer";
export default {
components: {Footer, Header},
}
</script>
<style scoped>
</style>

View File

@@ -1,57 +0,0 @@
import { Axios, Head, ColorMode, Tailwind, Translation, Content, Robots, SiteMap, Redirect } from './config'
export default {
head: Head,
target: 'server',
server: {
host: '0.0.0.0',
port: 3333
},
css: [
],
plugins: [
],
components: true,
buildModules: [
['@nuxtjs/tailwindcss', Tailwind],
['@nuxtjs/color-mode', ColorMode],
'nuxt-postcss8'
],
modules: [
['@nuxtjs/axios', Axios],
['nuxt-i18n', Translation],
['@nuxt/content', Content],
['@nuxtjs/robots', Robots],
['@nuxtjs/sitemap', SiteMap],
['@nuxtjs/redirect-module', Redirect]
],
buildDir: 'build',
build: {
postcss: {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
},
pageTransition: {
name: 'page',
mode: 'out-in',
},
loadingIndicator: {
name: 'circle',
color: '#3B8070',
background: 'white'
}
}

19
nuxt.config.ts Normal file
View File

@@ -0,0 +1,19 @@
import {defineNuxtConfig} from "@nuxtjs/composition-api";
import {NuxtConfig} from "@nuxt/types";
import head from './settings/Head'
import buildModules from './settings/BuildModules'
import modules from './settings/Modules'
import build from './settings/Build'
import arch from './settings/Arch'
import plugins from './settings/Plugins'
import css from './settings/Style'
export default defineNuxtConfig({
head,
modules,
...arch,
build,
plugins,
css,
buildModules
} as NuxtConfig)

View File

@@ -1,5 +1,5 @@
{
"name": "artsite",
"name": "nuxt-ts-app",
"version": "1.0.0",
"private": true,
"scripts": {
@@ -10,24 +10,28 @@
},
"dependencies": {
"@nuxt/content": "^1.14.0",
"@nuxtjs/axios": "5.13.1",
"@nuxtjs/redirect-module": "0.3.1",
"@nuxtjs/axios": "^5.13.1",
"@nuxtjs/composition-api": "^0.22.4",
"@nuxtjs/redirect-module": "^0.3.1",
"@nuxtjs/robots": "^2.5.0",
"@nuxtjs/sitemap": "^2.4.0",
"@tailwindcss/typography": "0.4.0",
"nuxt": "2.15.3",
"nuxt-i18n": "6.22.0",
"prism-themes": "1.6.0",
"sass": "1.32.8",
"sass-loader": "11.0.1"
"@nuxtjs/universal-storage": "^0.5.7",
"core-js": "^3.10.0",
"nuxt": "^2.15.3",
"nuxt-i18n": "^6.22.3",
"prism-themes": "^1.6.0",
"sass": "^1.32.8",
"windicss": "^2.5.11"
},
"devDependencies": {
"@nuxtjs/color-mode": "2.0.5",
"@nuxtjs/tailwindcss": "4.0.1",
"autoprefixer": "^10.2.5",
"css-loader": "5.2.0",
"nuxt-postcss8": "^1.1.2",
"postcss": "^8.2.6",
"tailwindcss": "^2.0.4"
"@nuxt/types": "^2.15.3",
"@nuxt/typescript-build": "^2.1.0",
"@nuxtjs/color-mode": "^2.0.5",
"fibers": "^5.0.0",
"nuxt-vite": "^0.0.36",
"nuxt-windicss": "^0.5.3",
"sass-loader": "^10.1.1",
"vite-plugin-windicss": "^0.11.3",
"vue-windicss-preprocess": "^2.2.0"
}
}

View File

@@ -1,272 +0,0 @@
<template>
<main class="about flex flex-col items-center px-5 xl:px-64">
<PageTitle
title="part.about"
color="orange"
>
<svg class="inline-block icon" height="40" width="40" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
</PageTitle>
<div class="flex flex-col md:flex-row justify-around items-center py-8">
<div>
<img class="logo-img rounded-full my-5" src="@/assets/img/Logo.jpg" alt="It's me !" />
</div>
<div class="ml-2 text-lg leading-6 md:w-2/3 text-justify">
<p>{{ $t('about.banner.hello') }} <span class="text-orange-400 font-bold">Arthur DANJOU</span> 👋.</p> <br/>
<p>{{ $t('about.banner.1')}}</p> <br/>
<p>{{ $t('about.banner.2') }}</p> <br/>
<p>{{ $t('about.banner.3') }}</p>
</div>
</div>
<div class="w-full mb-10 mt-4">
<h3 class="font-bold text-2xl md:text-4xl mb-3">
{{ $t('about.title.skills') }}
<svg class="inline icon" height="32" width="32" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
</svg>
</h3>
<div class="flex flex-row w-full overflow-x-auto md:overflow-x-hidden md:flex-wrap space-x-4 md:space-x-0 md:justify-start">
<div v-for="skill in skills">
<Skill
:skill="skill.title"
:color="skill.color"
:cover="skill.cover"
/>
</div>
</div>
</div>
<div class="w-full mb-10">
<h3 class="font-bold text-2xl md:text-4xl">
{{ $t('about.title.interests') }}
<svg height="32" width="32" class="inline icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 18.657A8 8 0 016.343 7.343S7 9 9 10c0-2 .5-5 2.986-7C14 5 16.09 5.777 17.656 7.343A7.975 7.975 0 0120 13a7.975 7.975 0 01-2.343 5.657z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.879 16.121A3 3 0 1012.015 11L11 14H9c0 .768.293 1.536.879 2.121z" />
</svg>
</h3>
<div>
<ul class="text-xl">
<li class="my-2">
{{ $t('about.title.technologies') }}
<svg class="inline icon" height="25" width="25" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z" />
</svg>
</li>
<li class="my-2">
{{ $t('about.interests.dev') }}
<svg class="inline icon" height="25" width="25" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
</svg>
</li>
<li class="my-2">
{{ $t('about.interests.devops') }}
<svg class="inline icon" height="25" width="25" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4" />
</svg>
</li>
<li class="my-2">
{{ $t('about.interests.startups') }}
<svg class="inline icon" height="25" width="25" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z" />
</svg>
</li>
<li class="my-2">
{{ $t('about.interests.sysadmin') }}
<svg class="inline icon" height="25" width="25" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01" />
</svg>
</li>
<li class="my-2">
{{ $t('about.interests.trips') }}
<svg class="inline icon" height="25" width="25" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
</svg>
</li>
<li class="my-2">
{{ $t('about.interests.moto') }}
<svg class="inline icon" height="25" width="25" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636" />
</svg>
</li>
</ul>
</div>
</div>
<div class="w-full mb-10">
<h3 class="font-bold text-2xl md:text-4xl">
{{ $t('about.title.languages') }}
<svg class="inline icon" height="32" width="32" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5h12M9 3v2m1.048 9.5A18.022 18.022 0 016.412 9m6.088 9h7M11 21l5-10 5 10M12.751 5C11.783 10.77 8.07 15.61 3 18.129" />
</svg>
</h3>
<div>
<table class="text-base text-xl">
<tr>
<td class="font-bold py-2 pr-4">{{ $t('about.languages.fr')}} 🇫🇷</td>
<td class="py-2 px-4">{{ $t('about.languages.native') }}</td>
</tr>
<tr>
<td class="font-bold py-2 pr-4">{{ $t('about.languages.en')}} 🇬🇧</td>
<td class="py-2 px-4">{{ $t('about.languages.fluent') }}</td>
</tr>
</table>
</div>
</div>
<div class="w-full mb-10">
<h3 class="font-bold text-2xl md:text-4xl mb-3">
{{ $t('about.title.formations') }}
<svg class="inline icon" height="32" width="32" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 14l9-5-9-5-9 5 9 5zm0 0l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14zm-4 6v-7.5l4-2.222" />
</svg>
</h3>
<div v-for="formation in formations">
<Formation
:title="formation.title"
:description="formation.description"
:location="formation.location"
:begin="formation.begin_date"
:end="formation.end_date" />
</div>
</div>
<div class="w-full mb-10">
<h3 class="font-bold text-2xl md:text-4xl mb-3">
{{ $t('about.title.experiences') }}
<svg class="inline icon" height="32" width="32" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 13v-1m4 1v-3m4 3V8M8 21l4-4 4 4M3 4h18M4 4h16v12a1 1 0 01-1 1H5a1 1 0 01-1-1V4z" />
</svg>
</h3>
<div v-for="experience in experiences">
<Experience
:title="experience.title"
:company="experience.company"
:location="experience.location"
:begin="experience.begin_date"
:end="experience.end_date" />
</div>
</div>
<nuxt-link to="/cv">
<div class="flex justify-center items-center font-bold py-4 px-6 bg-orange-400 hover:bg-orange-600 cursor-pointer duration-500 rounded-full dark:text-black">
{{ $t('about.cv') }}
<svg class="inline icon" height="32" width="32" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V8a2 2 0 00-2-2h-5m-4 0V5a2 2 0 114 0v1m-4 0a2 2 0 104 0m-5 8a2 2 0 100-4 2 2 0 000 4zm0 0c1.306 0 2.417.835 2.83 2M9 14a3.001 3.001 0 00-2.83 2M15 11h3m-3 4h2" />
</svg>
</div>
</nuxt-link>
<div class="mt-10 border-t-2 border-black dark:border-white border-solid w-full" />
<PageTitle
title="about.environment"
color="orange"
>
<svg class="inline icon" height="40" width="40" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 4a2 2 0 114 0v1a1 1 0 001 1h3a1 1 0 011 1v3a1 1 0 01-1 1h-1a2 2 0 100 4h1a1 1 0 011 1v3a1 1 0 01-1 1h-3a1 1 0 01-1-1v-1a2 2 0 10-4 0v1a1 1 0 01-1 1H7a1 1 0 01-1-1v-3a1 1 0 00-1-1H4a2 2 0 110-4h1a1 1 0 001-1V7a1 1 0 011-1h3a1 1 0 001-1V4z" />
</svg>
</PageTitle>
<p class="text-lg leading-6 text-justify pb-8">{{ $t('about.env.description') }}</p>
<EnvGroup>
<EnvTitle title="about.env.ide">
<svg class="inline icon" height="32" width="32" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
</svg>
</EnvTitle>
<EnvList>
<EnvListItem title="about.ide.java" content="Intellij Idea Ultimate" link="https://www.jetbrains.com/fr-fr/idea/"/>
<EnvListItem title="about.ide.web" content="WebStorm" link="https://www.jetbrains.com/fr-fr/webstorm/"/>
<EnvListItem title="about.ide.go" content="GoLand" link="https://www.jetbrains.com/fr-fr/go/"/>
<EnvListItem title="about.ide.db" content="DataGrip" link="https://www.jetbrains.com/fr-fr/datagrip/"/>
<EnvListItem title="about.ide.all" content="Jetbrains Toolbox" link="https://www.jetbrains.com/toolbox-app/"/>
<EnvListItem title="about.police" content="Jetbrains Mono" link="https://www.jetbrains.com/lp/mono/"/>
<EnvListItem title="about.console" content="Terminus" link="https://github.com/Eugeny/terminus"/>
<EnvListItem title="about.wsl_2" content="Ubuntu 20.04" link="https://www.microsoft.com/en-us/p/ubuntu-2004-lts/9n6svws3rx71?activetab=pivot:overviewtab"/>
</EnvList>
</EnvGroup>
<EnvGroup>
<EnvTitle title="about.env.apps">
<svg class="inline icon" height="32" width="32" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
</EnvTitle>
<EnvList>
<EnvListItem title="about.email_client" content="Courrier by Microsoft" link="https://www.microsoft.com/fr-fr/p/courrier-et-calendrier/9wzdncrfhvqm?activetab=pivot:overviewtab"/>
<EnvListItem title="about.vpn_client" content="Pritunl" link="https://pritunl.com/"/>
<EnvListItem title="about.ftp_client" content="WinSCP" link="https://winscp.net/eng/download.php"/>
<EnvListItem title="about.web_client" content="FireFox Developer Edition" link="https://www.mozilla.org/fr/firefox/developer/"/>
<EnvListItem title="about.organisation_tool" content="Notion" link="https://www.notion.so/"/>
<EnvListItem title="about.organisation_tool" content="Trello" link="https://www.trello.com/"/>
<EnvListItem title="about.design_tool" content="Affinity Designer" link="https://affinity.serif.com/fr/designer/"/>
<EnvListItem title="about.communication_tool" content="Slack" link="https://slack.com/intl/fr-fr/"/>
<EnvListItem title="about.communication_tool" content="Discord" link="https://www.discord.com/"/>
<EnvListItem title="about.communication_tool" content="Mattermost" link="https://mattermost.com/"/>
</EnvList>
</EnvGroup>
<EnvGroup>
<EnvTitle title="about.env.hosting">
<svg class="inline icon" height="32" width="32" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01" />
</svg>
</EnvTitle>
<EnvList>
<EnvListItem title="about.hosting.vps" content="PulseHeberg" link="https://pulseheberg.com/"/>
<EnvListItem title="about.hosting.ndd" content="OVH" link="https://ovh.com/"/>
</EnvList>
</EnvGroup>
<EnvGroup>
<EnvTitle title="about.env.setup">
<svg class="inline icon" height="25" width="25" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
</svg>
</EnvTitle>
<EnvList>
<EnvListItem title="about.setup.desk" content="Ikea"/>
<EnvListItem title="about.setup.phone" content="Samsung Galaxy Note 8" link="https://www.samsung.com/smartphones/galaxy-note8/"/>
<EnvListItem title="about.setup.computer" content="Asus i5, 8Go Ram, GTX 950, 1To HDD"/>
<EnvListItem title="about.setup.screen" content="iiyama ProLite E2283HS" link="https://iiyama.com/fr/fr/produits/prolite-e2283hs-b3/"/>
<EnvListItem title="about.setup.keyboard" content="Microsoft"/>
<EnvListItem title="about.setup.mouse" content="Roccat Kova" link="https://fr.roccat.org/Mice/Kova-AIMO"/>
<EnvListItem title="about.setup.headphone" content="Apple Airpods" link="https://www.apple.com/fr/airpods/"/>
<EnvListItem title="about.setup.microphone" content="Turtle Beach px22" link="https://www.amazon.fr/Turtle-Beach-PX22-casque-gaming/dp/B00BDS415I"/>
</EnvList>
</EnvGroup>
</main>
</template>
<script>
import EnvGroup from "~/components/EnvGroup.vue";
import EnvTitle from "~/components/EnvTitle.vue";
import EnvListItem from "~/components/EnvListItem.vue";
import EnvList from "~/components/EnvList.vue";
import Skill from "~/components/Skill.vue";
import Formation from "~/components/Formation.vue";
import Experience from "~/components/Experience.vue";
import PageTitle from "~/components/PageTitle";
export default {
name: "about",
components: {PageTitle, EnvList, EnvListItem, EnvTitle, EnvGroup, Skill, Formation, Experience},
head() {
return {
title: 'About me - Arthur Danjou'
}
},
async asyncData({ $content }) {
const skills = await $content('skills').fetch()
const experiences = await $content('experiences')
.sortBy('end_date', 'desc')
.fetch()
const formations = await $content('formations')
.sortBy('end_date', 'desc')
.fetch()
return {
skills,
experiences,
formations
}
}
}
</script>
<style scoped lang="scss">
.about {
.logo-img {
height: 20rem;
}
}
</style>

View File

@@ -1,276 +0,0 @@
<template>
<main class="blog flex flex-col items-center px-5 xl:px-64">
<PageTitle
title="part.blog"
color="green"
>
<svg class="inline-block icon" height="40" width="40" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
</svg>
</PageTitle>
<div class="flex flex-col mt-8 w-full md:w-1/2">
<h1
v-if="current_tag === ''"
class="text-lg mb-2"
>{{ $t('blog.tags.search') }}</h1>
<div
@click="resetPosts"
v-if="current_tag !== ''"
class="w-full"
>
<div class="w-full home-arrow flex cursor-pointer font-bold mb-3">
<div class="arrow duration-300 mr-2">
<svg height="25" width="25" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
</div>
{{ $t('blog.tags.back') }}
</div>
<div class="w-full">
{{ $t('blog.tags.current', { tag: $t(current_tag)}) }}
</div>
</div>
<div v-else class="flex flex-row w-full overflow-x-scroll md:overflow-x-hidden md:flex-wrap space-x-3 md:space-x-0">
<div v-for="tag in tags">
<div
class="mb-3 md:mr-4 border-b-2 border-opacity-0 hover:border-opacity-100 border-green-400 border-solid duration-300 cursor-pointer font-black"
@click="fetchPostsByTag(tag.slug)"
>
{{ $t(tag.slug) }}
</div>
</div>
</div>
</div>
<h1 v-if="posts.length === 0" class="text-xl font-bold text-center my-8 w-full">{{ $t('blog.no_posts') }}</h1>
<div class="w-full xl:w-1/2" v-else>
<div class="flex flex-col justify-around items-center py-8 w-full">
<div class="w-full" v-for="post in posts">
<nuxt-link :to="'/blog/' + post.slug">
<Post
:title="post.title"
:reading_time="post.reading_time"
:description="post.description"
:tags="displayTags(post.tags)"
:cover="post.cover"
:date="post.date"
:lightBg="post.background"
/>
</nuxt-link>
</div>
</div>
<div class="relative flex flex-row justify-between w-full mb-4" v-if="(next || prev) && this.postsCount > 5">
<div
class="duration-300 flex w-1/2 px-5 py-4 justify-center items-center"
:class="prev === null ? 'opacity-0': 'opacity-100'"
>
<div class="flex items-center duration-300 prev-arrow" @click="prevPage">
<div class="arrow duration-300">
<svg class="inline icon" height="30" width="30" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 15l-3-3m0 0l3-3m-3 3h8M3 12a9 9 0 1118 0 9 9 0 01-18 0z" />
</svg>
</div>
<div class="inline ml-4 font-bold">{{ $t('blog.pagination.prev') }}</div>
</div>
</div>
<div
class="duration-300 flex w-1/2 px-5 py-4 justify-center items-center"
:class="next === null ? 'opacity-0': 'opacity-100'"
>
<div class="flex items-center duration-300 suiv-arrow" @click="nextPage">
<div class="mr-4 font-bold">{{ $t('blog.pagination.next') }}</div>
<div class="inline arrow duration-300">
<svg class="inline icon" height="30" width="30" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 9l3 3m0 0l-3 3m3-3H8m13 0a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
</div>
</div>
</div>
</div>
</main>
</template>
<script>
import Post from "~/components/Post";
import PageTitle from "~/components/PageTitle";
export default {
name: "blog",
components: {PageTitle, Post},
head() {
return {
title: 'Blog - Arthur Danjou'
}
},
data () {
return {
postsCount: 0,
page: 0,
current_tag: '',
posts: []
}
},
methods: {
displayTags(tags) {
const tags_label = []
if (tags.length > 0) {
tags.map(tag => {
tags_label.push(tag)
})
}
return tags_label
},
async fetchPostsByTag(tag) {
this.current_tag = tag
this.page = 0
await this.fetchPosts()
if (this.posts.length !== 0) {
await this.fetchPrevAndNext()
} else {
this.next = null
this.prev = null
}
},
async resetPosts() {
this.current_tag = ''
this.posts = await this.$content(`articles/${this.$i18n.locale}`)
.sortBy('date', 'asc')
.limit(5)
.fetch()
},
async nextPage() {
this.page++
await this.fetchPosts()
await this.fetchPrevAndNext()
window.scrollTo({
top: 100,
behavior: "smooth"
})
},
async prevPage() {
this.page--
await this.fetchPosts()
await this.fetchPrevAndNext()
window.scrollTo({
top: 100,
behavior: "smooth"
})
},
async fetchPosts() {
let postsTemp = []
if (this.current_tag === "") {
postsTemp = await this.$content(`articles/${this.$i18n.locale}`)
.sortBy('date', 'asc')
.limit(5)
.skip(this.page * 5)
.fetch()
} else {
postsTemp = await this.$content(`articles/${this.$i18n.locale}`)
.sortBy('date', 'asc')
.limit(5)
.skip(this.page * 5)
.where({
tags: {
$contains: this.current_tag
}
})
.fetch()
}
const posts = []
postsTemp.map(post => {
posts.push(post)
})
this.posts = posts
},
async fetchPrevAndNext() {
const [_, next] = await this.$content(`articles/${this.$i18n.locale}`)
.surround(this.posts[this.posts.length - 1].slug, {
before: 1,
after: 1
})
.fetch()
const [prev, __] = await this.$content(`articles/${this.$i18n.locale}`)
.skip(this.page)
.surround(this.posts[0].slug, {
before: 1,
after: 1
})
.fetch()
this.prev = null
this.next = null
if (this.posts.length === 5) {
this.next = next
}
if (this.page > 0) {
this.prev = prev
}
}
},
async asyncData ({ $content, app }) {
const tags = await $content('tags').fetch()
const locale = await app.i18n.locale
const postsTemp = await $content(`articles/${locale}`)
.sortBy('date', 'asc')
.limit(5)
.fetch()
const posts = []
postsTemp.map(post => {
posts.push(post)
})
let prev = null
let next = null
if (posts.length > 0) {
const [_, nextTemp] = await $content(`articles/${locale}`)
.surround(posts[posts.length - 1].slug, {
before: 1,
after: 1
})
.fetch()
const [prevTemp, __] = await $content(`articles/${locale}`)
.surround(posts[0].slug, {
before: 1,
after: 1
})
.fetch()
next = nextTemp
prev = prevTemp
}
return {
posts,
postsCount: posts.length,
tags,
prev,
next
}
}
}
</script>
<style scoped lang="scss">
.blog {
.home-arrow:hover .arrow {
transform: translateX(-15px);
}
.prev-arrow:hover .arrow {
transform: translateX(-10px);
}
.suiv-arrow:hover .arrow {
transform: translateX(15px);
}
.arrow {
transform: translateX(-3px);
}
}
</style>

View File

@@ -1,210 +0,0 @@
<template>
<main class="contact flex flex-col items-center px-5 xl:px-64">
<PageTitle
title="part.contact"
color="purple"
>
<svg class="inline-block icon" height="40" width="40" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
</PageTitle>
<div class="w-full lg:w-3/4 mb-10 mt-4">
<h1 class="font-bold text-gray-700 text-xl md:text-3xl my-4 dark:text-dark-200">{{ $t('contact.newsletter.title') }}</h1>
<h3 class="text-md md:text-lg">
{{ $t('contact.newsletter.description') }} <br>
<span class="font-bold self-start">{{ $t('contact.newsletter.unfollow') }}</span>
</h3>
<form class="flex flex-col lg:flex-row mt-4 w-full">
<div class="flex flex-col lg:flex-row">
<div class="mb-3 lg:mr-4 w-full md:w-auto">
<input v-model="form.name"
class="select-text w-full placeholder-purple-700 dark:focus:bg-dark-800 dark:placeholder-purple-400 focus:bg-white duration-300 px-3 py-2 bg-purple-50 dark:bg-dark-900 border border-solid border-purple-700 rounded-lg"
type="text"
:placeholder="$t('contact.form.name')"
required
id="name"/>
</div>
<div class="mb-3 lg:mr-4 w-full md:w-auto">
<input v-model="form.email"
class="select-text w-full placeholder-purple-700 dark:focus:bg-dark-800 dark:placeholder-purple-400 focus:bg-white duration-300 px-3 py-2 bg-purple-50 dark:bg-dark-900 border border-solid border-purple-700 rounded-lg"
type="email"
:placeholder="$t('contact.form.mail')"
required
id="email"/>
</div>
</div>
<div class="mb-3 self-center">
<button @click.prevent="handleForm" class="dark:text-black font-bold px-3 py-2 bg-purple-400 hover:bg-purple-500 cursor-pointer duration-300 rounded-lg btn">
{{ $t('contact.form.submit')}}
<svg class="inline icon" height="25" width="25" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" />
</svg>
</button>
</div>
</form>
<div v-if="error" class="flex">
<div class="rounded-xl px-3 py-2 bg-red-300 font-bold dark:text-black">
{{ $t('contact.form.error') }}
</div>
</div>
<div v-if="success" class="flex">
<div class="rounded-xl px-3 py-2 bg-green-300 font-bold dark:text-black">
{{ $t('contact.form.success', { email: form.email }) }}
</div>
</div>
</div>
<div class="w-full lg:w-3/4 mb-10 mt-4">
<h1 class="font-bold text-gray-700 text-xl md:text-3xl my-4 dark:text-dark-100">
{{ $t('contact.how_to.title') }}
</h1>
<h3 class="text-md md:text-lg">
{{ $t('contact.how_to.description') }}
</h3>
<div class="mt-4 text-lg flex">
<div class="flex email duration-300 text-purple-500 hover:text-purple-700 cursor-pointer">
<a class="mr-2" href="mailto:me@arthurdanjou.fr?subject=Please enter here your project name">
me@arthurdanjou.fr
</a>
<div class="arrow duration-300">
<svg class="inline icon" height="25" width="25" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
</svg>
</div>
</div>
</div>
</div>
<div class="w-full lg:w-3/4 mb-10 mt-4">
<h1 class="font-bold text-gray-700 text-xl md:text-3xl my-4 dark:text-dark-100">
{{ $t('contact.available.title') }}
</h1>
<h3 class="text-lg md:text-lg">
{{ $t('contact.available.description') }}
</h3>
<div class="my-4 text-purple-500">
{{ $t('contact.available.start') }}
<span class="py-1 px-2 font-bold rounded-full m-0.5" :class="getColor">{{ $t('hiring.status.' + status) }}</span>
{{ $t('contact.available.end') }}
</div>
</div>
</main>
</template>
<script>
import PageTitle from "~/components/PageTitle";
export default {
name: "contact",
components: {PageTitle},
data () {
return {
status: '',
color: '',
form: {
name: '',
email: ''
},
success: false,
error: false
}
},
async asyncData({ $content }) {
const infos = await $content('infos').fetch()
return {
status: infos.hiring.status,
color: infos.hiring.color
}
},
methods: {
async handleForm () {
await this.$axios.post('subscribers',
{
email: this.form.email,
name: this.form.name
})
.then(() => {
this.success = true
setTimeout(() => {
this.success = false
this.form.email = ''
this.form.name = ''
}, 5000)
}).catch(() => {
this.error = true
setTimeout(() => {
this.error = false
}, 5000)
})
}
},
computed: {
getColor() {
switch (this.color) {
case 'red':
return 'bg-red-200 text-red-500'
case 'orange':
return 'bg-orange-200 text-orange-500'
case 'purple':
return 'bg-purple-200 text-purple-500'
case 'blue':
return 'bg-blue-200 text-blue-500'
case 'green':
return 'bg-green-200 text-green-500'
case 'yellow':
return 'bg-yellow-200 text-yellow-500'
case 'cyan':
return 'bg-cyan-200 text-cyan-500'
case 'teal':
return 'bg-teal-200 text-teal-500'
case 'amber':
return 'bg-amber-200 text-amber-500'
case 'blueGray':
return 'bg-blueGray-200 text-blueGray-500'
case 'emerald':
return 'bg-emerald-200 text-emerald-500'
case 'lightBlue':
return 'bg-lightBlue-200 text-lightBlue-500'
case 'lime':
return 'bg-lime-200 text-lime-500'
case 'rose':
return 'bg-rose-200 text-rose-500'
case 'black':
return 'bg-black text-black'
case 'white':
return 'bg-white text-white'
case 'pink':
return 'bg-pink-200 text-pink-500'
case 'fuchsia':
return 'bg-fuchsia-200 text-fuchsia-500'
case 'violet':
return 'bg-violet-200 text-violet-500'
case 'indigo':
return 'bg-indigo-200 text-indigo-500'
case 'warmGray':
return 'bg-warmGray-200 text-warmGray-500'
case 'trueGray':
return 'bg-trueGray-200 text-trueGray-500'
case 'gray':
return 'bg-gray-200 text-gray-500'
case 'coolGray':
return 'bg-coolGray-200 text-coolGray-500'
}
}
}
}
</script>
<style scoped lang="scss">
.contact {
.email:hover .arrow {
transform: translateX(15px);
}
.link {
@apply mr-5 duration-300;
&:hover {
@apply border-b-2 border-opacity-0 dark:border-opacity-0 dark:hover:border-opacity-100 hover:border-opacity-100 border-black dark:border-white border-solid;
}
}
}
</style>

View File

@@ -1,117 +0,0 @@
<template>
<main class="index px-5 xl:px-64">
<section class="mt-16 md:mt-32 banner w-full mb-16">
<div class="flex flex-col lg:flex-row-reverse mb-4">
<div class="hidden lg:block flex justify-center items-center lg:w-1/2">
<img src="@/assets/img/computer.png" alt="It's me !" class="icon" width="100%" height="100%"/>
</div>
<div class="mb-4 md:mb-10 lg:w-1/2 self-center">
<h1 class="text-4xl md:text-5xl text-left font-bold md:w-3/4">
{{ $t('home.banner.hello') }} <br/>
<span class="text-red-700 font-black">Arthur Danjou</span> 👋
</h1>
<p class="text-2xl md:text-3xl my-5 font-semibold">
{{ $t('home.banner.role') }}
</p>
<p class="text-lg md:text-2xl text-justify mb-8 leading-7 text-gray-700 dark:text-dark-200">
{{ $t('home.banner.description', {age: age}) }}
</p>
</div>
</div>
<div class="flex flex-col items-center w-full">
<div class="flex flex-col md:flex-row justify-around w-full md:mb-8">
<HomeLink
title="part.about"
description="part.about_description"
color="orange"
link="/about"
>
<svg class="inline" height="40" width="40" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
</svg>
</HomeLink>
<HomeLink
title="part.blog"
description="part.blog_description"
color="green"
link="/blog"
>
<svg class="inline" height="40" width="40" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"/>
</svg>
</HomeLink>
</div>
<div class="flex flex-col md:flex-row justify-around w-full">
<HomeLink
title="part.work"
description="part.work_description"
color="blue"
link="/work"
>
<svg class="inline-block" height="40" width="40" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 13.255A23.931 23.931 0 0112 15c-3.183 0-6.22-.62-9-1.745M16 6V4a2 2 0 00-2-2h-4a2 2 0 00-2 2v2m4 6h.01M5 20h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
</svg>
</HomeLink>
<HomeLink
title="part.contact"
description="part.contact_description"
color="purple"
link="/contact"
>
<svg class="inline-block" height="40" width="40" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"/>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"/>
</svg>
</HomeLink>
</div>
</div>
</section>
</main>
</template>
<script>
import Vue from 'vue'
import HomeLink from "~/components/HomeLink";
export default Vue.extend({
components: {HomeLink},
head() {
return {
title: 'Arthur Danjou - FullStack Web & Software Developer'
}
},
async asyncData({$content}) {
const infos = await $content('infos').fetch()
return {
age: infos.age
}
}
})
</script>
<style lang="scss" scoped>
.index {
.title {
line-height: 3rem;
}
.arrow-btn .icon {
transform: translate(3px, -5px);
transition-duration: .3s;
}
.arrow-btn:hover .icon {
transform: translate(3px, 0);
}
}
</style>

View File

@@ -1,150 +0,0 @@
<template>
<main class="px-5 xl:px-64 mb-16 md:mb-32">
<div class="w-full flex flex-col lg:flex-row items-center md:items-start mt-8 md:mt-32">
<div class="w-full lg:w-1/2 flex flex-col items-center">
<div class="md:mb-24">
<div class="mb-4 flex">
<nuxt-link to="/work" class="back-arrow flex">
<div class="duration-300 arrow">
<svg height="25" width="25" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
</div>
<div class="ml-2">
{{ $t('work.go_back') }}
</div>
</nuxt-link>
</div>
</div>
<img class="w-72 rounded-xl" :src="require(`@/assets/img/works/${work.cover}.png`)" alt="Project Img" />
<a
class="mt-4 py-3 px-6 rounded-full cursor-pointer duration-300 mb-10 lg:mb-0"
:class="getColor"
:href="work.url"
>{{work.url.replace('https://', '').replace('http://', '')}}</a>
</div>
<div class="w-full lg:w-1/2 ml-5 ">
<h1 class="text-xl lg:text-3xl font-bold">
{{ work.title }}
</h1>
<p class="mt-5 mb-10 text-md lg:text-lg text-gray-900 dark:text-dark-100">
{{ $t(work.description) }}
</p>
<div>
<h3 class="text-md lg:text-lg font-bold">
{{ $t('work.tech_used') }}
</h3>
<div class="flex flex-row w-full overflow-x-auto md:overflow-x-hidden md:flex-wrap space-x-4 md:space-x-0 md:justify-start">
<div v-for="skill in skills">
<WorkSkill
:skill="skill.title"
:color="skill.color"
:cover="skill.cover"
/>
</div>
</div>
</div>
</div>
</div>
</main>
</template>
<script>
import WorkSkill from "~/components/WorkSkill";
export default {
components: {WorkSkill},
head() {
return {
title: 'Work - Arthur Danjou'
}
},
data() {
return {
work: null
}
},
async asyncData({ params, $content, error }) {
const work = await $content('works', params.slug)
.fetch()
.catch(() => {
error({
statusCode: 404,
message: 'Work not found',
})
});
let skills = []
if (work) {
skills = await $content('skills').where({ slug: { $in: work.skills } }).fetch()
}
return {
work,
skills
}
},
computed: {
getColor() {
switch (this.work.color) {
case 'red':
return 'bg-red-400 hover:bg-red-600'
case 'orange':
return 'bg-orange-400 hover:bg-orange-600'
case 'purple':
return 'bg-purple-400 hover:bg-purple-600'
case 'blue':
return 'bg-blue-400 hover:bg-blue-600'
case 'green':
return 'bg-green-400 hover:bg-green-600'
case 'yellow':
return 'bg-yellow-400 hover:bg-yellow-600'
case 'cyan':
return 'bg-cyan-400 hover:bg-cyan-600'
case 'teal':
return 'bg-teal-400 hover:bg-teal-600'
case 'amber':
return 'bg-amber-400 hover:bg-amber-600'
case 'blueGray':
return 'bg-blueGray-400 hover:bg-blueGray-600'
case 'emerald':
return 'bg-emerald-400 hover:bg-emerald-600'
case 'lightBlue':
return 'bg-lightBlue-400 hover:bg-lightBlue-600'
case 'lime':
return 'bg-lime-400 hover:bg-lime-600'
case 'rose':
return 'bg-rose-400 hover:bg-rose-600'
case 'black':
return 'bg-black hover:bg-black'
case 'white':
return 'bg-white hover:bg-white'
case 'pink':
return 'bg-pink-400 hover:bg-pink-600'
case 'fuchsia':
return 'bg-fuchsia-400 hover:bg-fuchsia-600'
case 'violet':
return 'bg-violet-400 hover:bg-violet-600'
case 'indigo':
return 'bg-indigo-400 hover:bg-indigo-600'
case 'warmGray':
return 'bg-warmGray-400 hover:bg-warmGray-600'
case 'trueGray':
return 'bg-trueGray-400 hover:bg-trueGray-600'
case 'gray':
return 'bg-gray-400 hover:bg-gray-600'
case 'coolGray':
return 'bg-coolGray-400 hover:bg-coolGray-600'
}
}
}
}
</script>
<style scoped lang="scss">
.back-arrow:hover .arrow {
transform: translate(-8px, -1px);
}
.arrow {
transform: translate(3px, -1px);
}
</style>

View File

@@ -1,51 +0,0 @@
<template>
<main class="work flex flex-col items-center px-5 xl:px-64">
<PageTitle
title="part.work"
color="blue"
>
<svg class="inline-block icon" height="40" width="40" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 13.255A23.931 23.931 0 0112 15c-3.183 0-6.22-.62-9-1.745M16 6V4a2 2 0 00-2-2h-4a2 2 0 00-2 2v2m4 6h.01M5 20h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
</PageTitle>
<h1 v-if="works.length === 0" class="text-xl font-bold text-center my-8 w-full">{{ $t('work.no_work') }}</h1>
<div v-else class="flex flex-col justify-around items-center py-10 w-full">
<h1 class="text-xl font-bold text-center mb-8">{{ $t('work.description') }}</h1>
<div class="flex flex-col items-center md:items-start md:flex-row flex-wrap w-full space-y-3 md:space-y-0">
<div v-for="work in works">
<nuxt-link :to="'/work/' + work.slug">
<Work
:title="work.title"
:url="work.url"
:color="work.color"
:cover="work.cover"
/>
</nuxt-link>
</div>
</div>
</div>
</main>
</template>
<script>
import PageTitle from "~/components/PageTitle";
import Work from "~/components/Work";
export default {
name: "index",
components: {Work, PageTitle},
head() {
return {
title: 'Work - Arthur Danjou'
}
},
async asyncData({ $content }) {
const works = await $content('works').fetch()
return {
works
}
}
}
</script>
<style scoped lang="scss">
</style>

33
settings/Arch.ts Normal file
View File

@@ -0,0 +1,33 @@
const srcDir = 'src'
const dir = {
assets: 'assets',
layouts: 'layouts',
middleware: 'middlewares',
pages: 'pages',
static: 'static',
store: 'store',
}
const build = {
extractCss: true,
}
const pageTransition = {
name: 'page',
mode: 'out-in',
}
const target = 'server'
const server = {
port: 3333
}
const components = true
const buildDir = 'build'
const ssr = true
export default { srcDir, dir, build, pageTransition, target, server, buildDir, components, ssr }

4
settings/Build.ts Normal file
View File

@@ -0,0 +1,4 @@
// Build Configuration: https://go.nuxtjs.dev/config-build
export default {
}

47
settings/BuildModules.ts Normal file
View File

@@ -0,0 +1,47 @@
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
import {NuxtOptionsModule} from "@nuxt/types/config/module";
const color_mode = {
preference: 'system',
fallback: 'light',
classPrefix: '',
classSuffix: '',
}
const windicss = {
scan: {
dirs: [ './' ],
exclude: [
'node_modules',
'.git',
'.nuxt/**/*',
'build/**/*',
'*.template.html',
'app.html'
],
include: []
},
transformCSS: 'pre',
preflight: {
alias: {
// add nuxt aliases
'nuxt-link': 'a',
// @nuxt/image module
'nuxt-img': 'img',
}
}
}
const vite = {
vue: {
jsx: false
}
}
export default [
'@nuxt/typescript-build',
'@nuxtjs/composition-api',
['nuxt-windicss', windicss],
//['nuxt-vite', vite],
['@nuxtjs/color-mode', color_mode],
] as NuxtOptionsModule[]

41
settings/Head.ts Normal file
View File

@@ -0,0 +1,41 @@
// Global page headers: https://go.nuxtjs.dev/config-head
import {NuxtOptionsHead} from "@nuxt/types/config/head";
const params = {
title: 'artsite',
color: '#00a0ff',
image: '/images/image.jpg',
url: 'https://arthurdanjou.fr',
favicon: {
type: 'image/jpg',
href: '/favicon.png',
},
description:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ',
}
export default {
htmlAttrs: { lang: 'fr-FR' },
title: params.title,
meta: [
{ charset: 'utf-8' },
{ lang: 'fr-FR' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: params.description },
/**
* Open graph
* See : https://ogp.me/
*/
{ hid: 'og:type', name: 'og:type', content: 'website' },
{ hid: 'og:url', name: 'og:url', content: params.url },
{ hid: 'og:title', name: 'og:title', content: params.title },
{ hid: 'og:site_name', name: 'og:site_name', content: params.title },
{ hid: 'og:locale', name: 'og:locale', content: 'fr' },
{ hid: 'og:image', name: 'og:image', content: params.image },
{ name: 'msapplication-TileColor', content: params.color },
{ name: 'theme-color', content: params.color },
],
link: [{ rel: 'icon', type: params.favicon.type, href: params.favicon.href }],
} as NuxtOptionsHead

91
settings/Modules.ts Normal file
View File

@@ -0,0 +1,91 @@
import {NuxtOptionsModule} from "@nuxt/types/config/module";
const axios = {
credentials: true,
baseURL: 'https://api.arthurdanjou.fr'
}
const i18n = {
locales: [
{
code: 'en',
name: 'English',
iso: 'en-EN',
file: 'en-EN.ts',
},
{
code: 'fr',
name: 'Français',
iso: 'fr-FR',
file: 'fr-FR.ts'
},
],
strategy: 'no_prefix',
defaultLocale: 'en',
langDir: 'locales/',
lazy: true,
seo: true,
vueI18n: {
fallbackLocale: 'en',
},
}
const content = {
apiPrefix: 'api',
nestedProperties: ['skills.slug'],
markdown: {
prism: {
theme: 'prism-themes/themes/prism-darcula.css'
},
remarkPlugins: [
'remark-squeeze-paragraphs',
'remark-slug',
'remark-autolink-headings',
'remark-external-links',
'remark-footnotes',
],
}
}
const storage = {
cookie: {
prefix: 'artsite',
options: {
path: '/'
}
},
}
const sitemap = {
path: '/sitemap.xml',
hostname: 'https://arthurdanjou.fr',
cacheTime: 720000,
gzip: true,
generate: false,
}
const robots = {
UserAgent: '*',
Sitemap: 'https://arthurdanjou.fr/sitemap.xml',
Allow: '*'
}
const redirect = [
{ from: '/source', to: 'https://github.com/arthurdanjou/artsite' },
{ 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' }
]
export default [
['@nuxtjs/axios', axios],
['nuxt-i18n', i18n],
['@nuxt/content', content],
['@nuxtjs/universal-storage', storage],
['@nuxtjs/robots', robots],
['@nuxtjs/sitemap', sitemap],
['@nuxtjs/redirect-module', redirect]
] as NuxtOptionsModule[]

4
settings/Plugins.ts Normal file
View File

@@ -0,0 +1,4 @@
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
export default [
{ src: '~/plugins/i18n.ts' }
]

4
settings/Style.ts Normal file
View File

@@ -0,0 +1,4 @@
// Global CSS: https://go.nuxtjs.dev/config-css
export default [
'@/assets/css/style.scss'
]

67
src/assets/css/style.scss Normal file
View File

@@ -0,0 +1,67 @@
@import url('https://fonts.googleapis.com/css2?family=Raleway&display=swap');
.icon {
transform: translate(3px, -3px);
z-index: 1;
}
img, svg {
position: static;
}
body {
@apply dark:bg-black dark:text-white
}
* {
@apply select-none outline-none;
font-family: 'Raleway', sans-serif;
}
.nuxt-content-editor {
@apply dark:(bg-dark-800 text-white) border dark:border-white border-black border-solid;
}
//TODO remove with windicss/typography
.nuxt-content-container {
p {
@apply text-gray-700 dark:text-gray-400
}
h1, h2, h3, h4, h5, h6 {
@apply font-bold text-black dark:text-white mt-8 mb-4
}
ul {
@apply list-inside list-disc my-4 text-gray-700 dark:text-gray-400
}
p, li {
@apply text-lg
}
h1 {
@apply text-4xl
}
h2 {
@apply text-3xl
}
h3 {
@apply text-2xl
}
h4 {
@apply text-xl
}
h5 {
@apply text-lg
}
h6 {
@apply text-sm
}
}

View File

Before

Width:  |  Height:  |  Size: 185 KiB

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

Before

Width:  |  Height:  |  Size: 457 KiB

After

Width:  |  Height:  |  Size: 457 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m256 0c-140.699219 0-256 116.300781-256 257 0 139.882812 114.25 255 256 255 141.574219 0 256-114.945312 256-255 0-140.699219-115.300781-257-256-257zm45 477.5c-14.398438 3-29.699219 4.5-45 4.5s-30.601562-1.5-45-4.5v-70.199219c0-16.800781 4.5-22.800781 10.5-30.902343 3.054688-3.492188 4.898438-6.625 18.597656-27.296876l-23.097656-3.601562c-59.402344-8.699219-82.800781-39.601562-92.101562-63.601562-12-32.097657-5.699219-72.300782 15.902343-97.796876 3.300781-3.902343 6-10.503906 3.601563-17.402343-4.503906-13.800781-3.902344-35.699219-.902344-44.101563 15.90625 2.273438 32.261719 13.667969 45.902344 21.902344 6.285156 3.667969 9.582031 2.699219 12.597656 3 10.960938-2.28125 28.058594-7.800781 54.300781-7.800781 16.199219 0 33.300781 2.398437 50.101563 7.199219 3.003906-.070313 7.832031 2.484374 16.199218-2.398438 14.257813-8.6875 30.058594-19.691406 45.898438-21.902344 3 8.402344 3.601562 30.300782-.898438 44.101563-2.402343 6.898437.296876 13.5 3.601563 17.402343 21.597656 25.5 27.898437 65.699219 15.898437 97.796876-9.300781 24-32.699218 54.902343-92.101562 63.601562l-23.097656 3.601562c14.160156 21.367188 15.652344 23.929688 18.601562 27.296876 5.996094 8.101562 10.496094 14.101562 10.496094 30.902343zm30-8.699219v-61.5c0-17.101562-3.601562-28.5-8.402344-36.902343 45.601563-12.296876 78.003906-39.300782 92.402344-78 15.300781-40.796876 8.402344-89.398438-17.101562-123 4.503906-20.097657 4.503906-52.199219-6.296876-67.199219-4.800781-6.597657-11.402343-10.199219-19.800781-10.199219-.300781 0-.300781 0-.300781 0-23.261719 1.257812-41.570312 12.972656-61.199219 24.898438-18-4.800782-36.300781-7.199219-54.601562-7.199219-18.597657 0-37.199219 2.699219-53.695313 7.199219-20.664062-12.460938-38.796875-23.671876-62.703125-24.898438-7.5 0-14.101562 3.601562-18.902343 10.199219-10.796876 15-10.796876 47.101562-6.296876 67.199219-25.503906 33.601562-32.402343 82.5-17.101562 123 14.398438 38.699218 46.800781 65.703124 92.402344 78-3.722656 6.511718-6.667969 14.914062-7.828125 26.285156-9.210938 3.175781-17.199219 4.210937-24.628907 2.027344-7.835937-2.316407-13.941406-7.546876-19.246093-16.46875-11.914063-20.015626-32.207031-36.355469-55.3125-34.230469l2.636719 29.882812c10.699218-.980469 21.347656 10.339844 26.878906 19.671875 9.125 15.367188 21.417968 25.445313 36.546875 29.914063 11.230469 3.308593 21.496093 3.230469 32.550781.871093v40.449219c-87.300781-30.601562-151-114-151-211.800781 0-124.199219 101.800781-227 226-227s226 102.800781 226 227c0 97.800781-63.699219 181.199219-151 211.800781zm0 0"/></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<path d="M256,0C115.301,0 0,116.301 0,257C0,396.883 114.25,512 256,512C397.574,512 512,397.055 512,257C512,116.301 396.699,0 256,0ZM301,477.5C286.602,480.5 271.301,482 256,482C240.699,482 225.398,480.5 211,477.5L211,407.301C211,390.5 215.5,384.5 221.5,376.398C224.555,372.906 226.398,369.773 240.098,349.102L217,345.5C157.598,336.801 134.199,305.898 124.898,281.898C112.898,249.801 119.199,209.598 140.801,184.102C144.102,180.199 146.801,173.598 144.402,166.699C139.898,152.898 140.5,131 143.5,122.598C159.406,124.871 175.762,136.266 189.402,144.5C195.688,148.168 198.984,147.199 202,147.5C212.961,145.219 230.059,139.699 256.301,139.699C272.5,139.699 289.602,142.098 306.402,146.898C309.406,146.828 314.234,149.383 322.602,144.5C336.859,135.813 352.66,124.809 368.5,122.598C371.5,131 372.102,152.898 367.602,166.699C365.199,173.598 367.898,180.199 371.203,184.102C392.801,209.602 399.102,249.801 387.102,281.898C377.801,305.898 354.402,336.801 295,345.5L271.902,349.102C286.063,370.469 287.555,373.031 290.504,376.398C296.5,384.5 301,390.5 301,407.301L301,477.5ZM331,468.801L331,407.301C331,390.199 327.398,378.801 322.598,370.398C368.199,358.102 400.602,331.098 415,292.398C430.301,251.602 423.402,203 397.898,169.398C402.402,149.301 402.402,117.199 391.602,102.199C386.801,95.602 380.199,92 371.801,92L371.5,92C348.238,93.258 329.93,104.973 310.301,116.898C292.301,112.098 274,109.699 255.699,109.699C237.102,109.699 218.5,112.398 202.004,116.898C181.34,104.438 163.207,93.227 139.301,92C131.801,92 125.199,95.602 120.398,102.199C109.602,117.199 109.602,149.301 114.102,169.398C88.598,203 81.699,251.898 97,292.398C111.398,331.098 143.801,358.102 189.402,370.398C185.68,376.91 182.734,385.313 181.574,396.684C172.363,399.859 164.375,400.895 156.945,398.711C149.109,396.395 143.004,391.164 137.699,382.242C125.785,362.227 105.492,345.887 82.387,348.012L85.023,377.895C95.723,376.914 106.371,388.234 111.902,397.566C121.027,412.934 133.32,423.012 148.449,427.48C159.68,430.789 169.945,430.711 181,428.352L181,468.801C93.699,438.199 30,354.801 30,257C30,132.801 131.801,30 256,30C380.199,30 482,132.801 482,257C482,354.801 418.301,438.199 331,468.801Z" style="fill:white;fill-rule:nonzero;"/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 573 B

After

Width:  |  Height:  |  Size: 573 B

View File

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 702 B

View File

@@ -0,0 +1,43 @@
<template>
<section v-if="info && info.age" class="w-full flex items-center justify-center my-12">
<div class="flex flex-col md:flex-row justify-between items-center">
<div class="mb-12 md:mb-0 md:w-1/2 flex justify-center">
<img src="@/assets/images/memojies/Hey.png" alt="It's me !" class="w-1/2">
</div>
<div class="md:w-1/2 text-justify">
<h2 class="text-4xl font-bold text-center md:text-justify">
Who am I ?
</h2>
<p class="text-xl my-6 text-gray-700 dark:text-gray-400">
{{ $t('home.banner.description', {age: info.age}) }}
</p>
<div class="flex justify-center md:justify-start">
<Button content="Decouvrir mon profil" link="about"/>
</div>
</div>
</div>
</section>
</template>
<script lang="ts">
import {useAsync, useContext} from "@nuxtjs/composition-api";
import {InfoData} from "../../@types/types";
export default {
name: "AboutPreview",
setup() {
const {$content} = useContext()
const info = useAsync(() => {
return $content('infos').fetch<InfoData>()
})
return {
info
}
}
}
</script>
<style scoped lang="scss">
</style>

43
src/components/Ad.vue Normal file
View File

@@ -0,0 +1,43 @@
<template>
<div class="rounded-3xl p-2 lg:p-8 text-center" :class="getColor">
<slot />
</div>
</template>
<script lang="ts">
import {computed} from "@nuxtjs/composition-api";
interface AdProps {
color: string
}
export default {
name: "Ad",
props: {
color: {
type: String,
default: 'red'
}
},
setup(props: AdProps) {
const getColor = computed(() => {
switch (props.color) {
case 'red':
return 'bg-red-300'
case 'blue':
return 'bg-blue-300'
case 'rose':
return 'bg-rose-300'
}
})
return {
getColor
}
}
}
</script>
<style scoped lang="scss">
</style>

46
src/components/AdHome.vue Normal file
View File

@@ -0,0 +1,46 @@
<template>
<section class="w-full my-12">
<div class="md:space-x-12 space-y-8 md:space-y-0 flex flex-col md:flex-row items-center justify-around h-full">
<nuxt-link to="/uses" class="md:w-1/3 h-full">
<Ad color="rose" class="w-full flex flex-col justify-between items-center">
<div>
<img class="h-48" src="~/assets/images/memojies/Dev.png" alt="Dev Memoji" />
</div>
<div>
<h1 class="font-bold text-black text-4xl">
Comment je travaille ?
</h1>
<h3 class="px-4 text-xl text-gray-700">
Venez decouvrir mon environnement de developpement
</h3>
</div>
</Ad>
</nuxt-link>
<nuxt-link to="/contact" class="md:w-1/3 h-full">
<Ad color="blue" class="w-full flex flex-col justify-between items-center">
<div>
<img class="h-48" src="~/assets/images/memojies/Fiesta.png" alt="Fiesta Memoji" />
</div>
<div>
<h1 class="font-bold text-black text-4xl">
Vous avez un projet ?
</h1>
<h3 class="px-4 text-lg text-gray-700">
Contactez moi en detaillant votre projet pour debuter notre collaboration.
</h3>
</div>
</Ad>
</nuxt-link>
</div>
</section>
</template>
<script lang="ts">
export default {
name: "AdPreview"
}
</script>
<style scoped lang="scss">
</style>

30
src/components/Banner.vue Normal file
View File

@@ -0,0 +1,30 @@
<template>
<section class="my-16 md:my-32 w-full flex items-center justify-center">
<div class="text-center flex flex-col items-center">
<h1 class="text-6xl font-bold text-gray-700 dark:text-gray-400">
Hello, I am <span class="text-black dark:text-white">Arthur Danjou</span> 👋,
</h1>
<h2 class="my-6 text-4xl text-black dark:text-white">
a <strong>Web</strong> and <strong>Software Developer</strong>. <br />
I am also a <strong>Student</strong>.
</h2>
<p class="mt-4 text-lg text-gray-800 mb-10 dark:text-gray-300">You can follow me on <span class="link">Twitter</span>,
<span class="link">Twitch</span>
and <span class="link">Github</span>.
Here is my <nuxt-link to="contact" class="link">Contact</nuxt-link> page.
</p>
</div>
</section>
</template>
<script lang="ts">
export default {
name: "Banner"
}
</script>
<style scoped lang="scss">
.link {
@apply font-medium cursor-pointer border-b-2 border-gray-200 text-indigo-600 hover:border-indigo-600 duration-200 dark:(font-white border-gray-700) hover:dark:border-indigo-600
}
</style>

26
src/components/Button.vue Normal file
View File

@@ -0,0 +1,26 @@
<template>
<nuxt-link :to="link" class="duration-150 transform hover:scale-105">
<div class="text-lg cursor-pointer px-8 py-4 rounded-xl border-2 border-indigo-600 hover:(bg-indigo-600 text-white) dark:hover:text-black text-indigo-600 duration-300">
{{ content }}
</div>
</nuxt-link>
</template>
<script lang="ts">
export default {
name: "Button",
props: {
content: {
type: String,
default: 'Content'
},
link: {
type: String,
default: '/'
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,91 @@
<template>
<section class="w-full flex items-center justify-center flex-col">
<h2 class="text-center mb-10 font-bold text-gray-700 text-2xl md:text-3xl my-4 dark:text-gray-400">
Fill in the form or <br class="lg:hidden"/><a class="email text-black dark:text-white" href="mailto:me@arthurdanjou.fr" target="_blank">Send an email</a> 📬
</h2>
<form class="w-full lg:w-1/2">
<div class="w-full lg:flex lg:space-x-4 justify-center mb-8 lg:mb-12">
<div class="form-div lg:w-1/2 mb-8 lg:mb-0">
<input
id="name"
required
type="text"
placeholder=" "
class="form-input-half w-full"
/>
<label for="name" class="form-label"> What is your name ?</label>
</div>
<div class="form-div lg:w-1/2">
<input
id="email"
required
type="email"
placeholder=" "
class="form-input-half w-full"
/>
<label for="email" class="form-label">What is your email ?</label>
</div>
</div>
<div class="form-div w-full mb-8 lg:mb-12">
<input
id="subject"
required
type="text"
placeholder=" "
class="form-input w-full"
/>
<label for="subject" class="form-label">Why are you contacting me?</label>
</div>
<div class="form-div w-full">
<textarea
id="content"
required
placeholder=" "
class="form-input w-full"
minlength="30"
rows="4"
/>
<label for="content" class="form-label">Tell me about your project</label>
</div>
</form>
<div class="my-12">
<div class="font-bold px-6 py-3 border-2 rounded-full border-indigo-600 text-indigo-600 hover:(bg-indigo-600 text-white) hover:dark:text-black duration-300 cursor-pointer">
Envoyer
</div>
</div>
</section>
</template>
<script lang="ts">
export default {
name: "ContactForm"
}
</script>
<style scoped lang="scss">
input:focus-within ~ label, textarea:focus-within ~ label,
input:not(:placeholder-shown) ~ label, textarea:not(:placeholder-shown) ~ label {
@apply transform scale-75 -translate-y-6 -translate-x-7;
}
.form-input-half:focus-within ~ label,
.form-input-half:not(:placeholder-shown) ~ label {
@apply transform scale-75 -translate-y-6 -translate-x-5;
}
.form-div {
@apply relative border-b border-gray-200 dark:border-gray-800 focus-within:border-black dark:focus-within:border-white
}
.form-input-half, .form-input {
@apply block w-full appearance-none focus:outline-none bg-transparent
}
.form-label {
@apply absolute top-0 -z-1 duration-300 text-gray-700 dark:text-gray-400
}
.email {
@apply duration-300 border-b-2 border-gray-200 dark:border-gray-800 hover:(border-black dark:border-white)
}
</style>

View File

@@ -1,7 +1,7 @@
<template>
<div class="w-full mb-10">
<section class="w-full mb-10">
<slot />
</div>
</section>
</template>
<script>

View File

@@ -1,5 +1,5 @@
<template>
<ul class="list-disc ml-10 text-gray-600 dark:text-dark-100 text-xl">
<ul class="list-disc ml-10 text-gray-700 dark:text-gray-400 text-xl">
<slot/>
</ul>
</template>

View File

@@ -1,7 +1,7 @@
<template>
<li>
{{ $t(title) }}:
<a class="duration-300 text-orange-400 font-medium border-b-2 border-opacity-0 hover:border-opacity-100 border-orange-400 border-solid" v-if="link" :href="link" target="_blank">{{ content }}</a>
<a class="duration-300 text-indigo-600 font-medium border-b-2 border-opacity-0 hover:border-opacity-100 border-indigo-600 border-solid" v-if="link" :href="link" target="_blank">{{ content }}</a>
<span v-else>{{ content }}</span>
</li>
</template>

View File

@@ -0,0 +1,78 @@
<template>
<div class="flex flex-row mb-5">
<div class="self-center flex h-3 w-3 mr-3 relative">
<span v-if="end === 'Today'" class="animate-ping relative inline h-3 w-3 rounded-full bg-indigo-600 opacity-75"></span>
<span v-else class="inline relative h-3 w-3 rounded-full bg-gray-400 opacity-75"></span>
<span v-if="end === 'Today'" class="inline absolute rounded-full h-3 w-3 bg-indigo-800"></span>
<span v-else class="inline absolute rounded-full h-3 w-3 bg-gray-500"></span>
</div>
<div class="leading-7">
<p v-if="isSameDate()" class="text-base dark:text-dark-100 text-gray-800 leading-6">{{ getBeginDate }} <span class="px-3">|</span> {{location}}</p>
<p v-else class="text-base dark:text-dark-100 text-gray-800 leading-6">{{ getBeginDate }} - {{ getEndDate }} <span class="px-3">|</span> {{location}}</p>
<h1 class="text-2xl font-bold">{{ $t(title) }}</h1>
<h2 class="text-xl text-gray-700 dark:text-gray-400">{{ company }}</h2>
</div>
</div>
</template>
<script lang="ts">
import {computed, useContext} from "@nuxtjs/composition-api";
interface ExperienceProps {
title: string,
company: string,
location: string,
begin: string,
end: string
}
export default {
name: "Experience",
props: {
title: {
type: String,
default: "Title"
},
company: {
type: String,
default: "ArtDanjProduction"
},
location: {
type: String,
default: "France"
},
begin: {
type: String,
default: "Now"
},
end: {
type: String,
default: "Never"
}
},
setup(props: ExperienceProps) {
const {i18n} = useContext()
const getBeginDate = computed(() => {
const dateFormat = props.begin.split('-')
return i18n.t('month.' + dateFormat[0]) + " " + dateFormat[1]
})
const getEndDate = computed(() => {
const dateFormat = props.end.split('-')
return props.end === 'Today' ? i18n.t('date.today') : i18n.t('month.' + dateFormat[0]) + " " + dateFormat[1]
})
const isSameDate = () => {
return props.begin === props.end
}
return {
getBeginDate,
getEndDate,
isSameDate
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,44 @@
<template>
<section class="w-full mb-10">
<h3 class="font-bold text-2xl md:text-4xl mb-3">
{{ $t('about.title.experiences') }}
<svg class="inline icon" height="32" width="32" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 13v-1m4 1v-3m4 3V8M8 21l4-4 4 4M3 4h18M4 4h16v12a1 1 0 01-1 1H5a1 1 0 01-1-1V4z" />
</svg>
</h3>
<div v-if="experiences" v-for="experience in experiences">
<Experience
:title="experience.title"
:company="experience.company"
:location="experience.location"
:begin="experience.begin_date"
:end="experience.end_date" />
</div>
</section>
</template>
<script lang="ts">
import {useAsync, useContext} from "@nuxtjs/composition-api";
import {Experience} from "../../@types/types";
export default {
name: "ExperiencesAbout",
setup() {
const {$content} = useContext()
const experiences = useAsync(() => {
return $content('experiences')
.sortBy('end_date', 'desc')
.fetch<Experience>()
})
return {
experiences
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,26 +1,27 @@
<template>
<footer class="footer w-full border-t-2 border-solid border-black dark:border-white mb-20 md:mb-0">
<footer class="footer w-full border-t-2 border-solid border-gray-200 dark:border-gray-800 mb-20 md:mb-0">
<div>
<div class="flex flex-col items-center py-4 text-center ">
<div class="mb-3">
<p class="inline">{{ $t('footer.find_me') }}
<br class="md:hidden"/>
<a class="font-semibold" href="https://twitch.com/ArthurDanjou" target="_blank" rel="noopener noreferrer">
<img class="inline img" src="@/assets/img/socials/twitch.svg" alt="Twitch logo" height="20" width="20" />
<img class="inline" src="@/assets/images/socials/twitch.svg" alt="Twitch logo" height="20" width="20" />
<span class="link">Twitch</span>
</a>,
<a class="font-semibold" href="https://github.com/ArthurDanjou" target="_blank" rel="noopener noreferrer">
<img class="inline img" src="@/assets/img/socials/github.svg" alt="Github logo" height="20" width="20" />
<img v-if="!isDarkMode" class="inline" src="@/assets/images/socials/github-black.svg" alt="Github logo" height="20" width="20" />
<img v-else class="inline" src="@/assets/images/socials/github-white.svg" alt="Github logo" height="20" width="20" />
<span class="link">Github</span>
</a> &
<a class="font-semibold" href="https://twitter.com/ArthurDanj" target="_blank" rel="noopener noreferrer">
<img class="inline img" src="@/assets/img/socials/twitter.svg" alt="Twitter logo" height="20" width="20" />
<img class="inline" src="@/assets/images/socials/twitter.svg" alt="Twitter logo" height="20" width="20" />
<span class="link">Twitter</span>
</a>
<br class="md:hidden"/>
{{ $t('footer.separator') }}
<a class="font-semibold" href="mailto:contact@arthurdanjou.fr" target="_blank" rel="noopener noreferrer">
<svg class="inline img" width="20" height="20" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<svg class="inline" width="20" height="20" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
<span class="link">Mail</span>
@@ -34,28 +35,33 @@
<p>
{{ $t('footer.credits') }}
<a class="font-semibold" target="_blank" href="https://nuxtjs.org" rel="noopener noreferrer">
<img class="inline img" src="@/assets/img/socials/nuxtjs.svg" alt="NuxtJs logo" height="20" width="20" />
<img class="inline" src="@/assets/images/socials/nuxtjs.svg" alt="NuxtJs logo" height="20" width="20" />
<span class="link">NuxtJs</span>
</a>
&
<a class="font-semibold" target="_blank" href="https://preview.adonisjs.com/" rel="noopener noreferrer">
<img class="inline img" src="@/assets/img/socials/adonisjs.svg" alt="AdonisJs logo" height="20" width="20" />
<span class="link">AdonisJs</span>
</a>
{{ $t('footer.credits_separator') }} <span>Arthur DANJOU</span>
</p>
<p>{{ $t('footer.copyrights', { date: date }) }}</p>
<p>{{ $t('footer.copyrights', { date: getDate }) }}</p>
</div>
</div>
</footer>
</template>
<script>
import {computed, ref, useContext} from "@nuxtjs/composition-api";
export default {
name: "Footer",
data () {
setup() {
const {$colorMode} = useContext()
const isDarkMode = computed(() => {
return $colorMode.preference === 'dark' | undefined
})
const getDate = ref(new Date().getFullYear())
return {
date: new Date().getFullYear()
getDate,
isDarkMode
}
}
}
@@ -63,16 +69,8 @@ export default {
<style scoped lang="scss">
.footer {
.img {
transform: translateY(-3px);
}
.link {
@apply duration-300;
&:hover {
@apply border-b-2 border-opacity-0 dark:border-opacity-0 dark:hover:border-opacity-100 hover:border-opacity-100 border-black dark:border-white border-solid;
}
@apply border-b-2 border-gray-200 hover:border-black dark:border-gray-700 dark:hover:border-white duration-300;
}
}
</style>

View File

@@ -0,0 +1,73 @@
<template>
<div class="flex flex-row mb-5">
<div class="self-center flex h-3 w-3 mr-3 relative">
<span v-if="end === 'Today'" class="animate-ping relative inline h-3 w-3 rounded-full bg-indigo-600 opacity-75"></span>
<span v-else class="inline relative h-3 w-3 rounded-full bg-gray-400 opacity-75"></span>
<span v-if="end === 'Today'" class="inline absolute rounded-full h-3 w-3 bg-indigo-800"></span>
<span v-else class="inline absolute rounded-full h-3 w-3 bg-gray-500"></span>
</div>
<div class="leading-7">
<p class="text-base dark:text-dark-100 text-gray-800 leading-6">{{ getBeginDate }} - {{ getEndDate }} <span class="px-3">|</span> {{location}}</p>
<h1 class="text-2xl font-bold">{{ $t(title) }}</h1>
<h2 class="text-xl text-gray-700 dark:text-gray-400">{{ $t(description) }}</h2>
</div>
</div>
</template>
<script lang="ts">
import {computed, useContext} from "@nuxtjs/composition-api";
interface FormationProps {
title: string,
description: string,
location: string,
begin: string,
end: string
}
export default {
name: "Formation",
props: {
title: {
type: String,
default: "Title"
},
description: {
type: String,
default: "Description"
},
location: {
type: String,
default: "Location"
},
begin: {
type: String,
default: "Now"
},
end: {
type: String,
default: "Never"
}
},
setup(props: FormationProps) {
const {i18n} = useContext()
const getBeginDate = computed(() => {
const dateFormat = props.begin.split('-')
return i18n.t('month.' + dateFormat[0]) + " " + dateFormat[1]
})
const getEndDate = computed(() => {
const dateFormat = props.end.split('-')
return props.end === 'Today' ? i18n.t('date.today') : i18n.t('month.' + dateFormat[0]) + " " + dateFormat[1]
})
return {
getBeginDate,
getEndDate
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,44 @@
<template>
<div class="w-full mb-10">
<h3 class="font-bold text-2xl md:text-4xl mb-3">
{{ $t('about.title.formations') }}
<svg class="inline icon" height="32" width="32" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 14l9-5-9-5-9 5 9 5zm0 0l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14zm-4 6v-7.5l4-2.222" />
</svg>
</h3>
<div v-if="formations" v-for="formation in formations">
<Formation
:title="formation.title"
:description="formation.description"
:location="formation.location"
:begin="formation.begin_date"
:end="formation.end_date" />
</div>
</div>
</template>
<script lang="ts">
import {useAsync, useContext} from "@nuxtjs/composition-api";
import {Formation} from "../../@types/types";
export default {
name: "FormationsHome",
setup() {
const {$content} = useContext()
const formations = useAsync(() => {
return $content('formations')
.sortBy('end_date', 'desc')
.fetch<Formation>()
})
return {
formations
}
}
}
</script>
<style scoped>
</style>

Some files were not shown because too many files have changed in this diff Show More