Merge branch 'dev'
# Conflicts: # package.json # yarn.lock
37
.github/workflows/node.js.yml
vendored
@@ -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
@@ -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
@@ -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
@@ -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 }
|
||||
0
vue-shim.d.ts → @types/vue-shim.d.ts
vendored
2
LICENSE
@@ -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
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Raleway&display=swap');
|
||||
@import "./style.scss";
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
Before Width: | Height: | Size: 186 KiB |
@@ -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 |
@@ -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 |
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -1,4 +0,0 @@
|
||||
export default {
|
||||
credentials: true,
|
||||
baseURL: 'https://api.arthurdanjou.fr/'
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
export default {
|
||||
preference: 'system',
|
||||
fallback: 'light',
|
||||
classPrefix: '',
|
||||
classSuffix: '',
|
||||
}
|
||||
@@ -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',
|
||||
],
|
||||
}
|
||||
}
|
||||
@@ -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' }
|
||||
]
|
||||
}
|
||||
@@ -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' },
|
||||
]
|
||||
@@ -1,5 +0,0 @@
|
||||
export default {
|
||||
UserAgent: '*',
|
||||
Sitemap: 'https://arthurdanjou.fr/sitemap.xml',
|
||||
Allow: '*'
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
export default {
|
||||
path: '/sitemap.xml',
|
||||
hostname: 'https://arthurdanjou.fr',
|
||||
cacheTime: 720000,
|
||||
gzip: true,
|
||||
generate: false,
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
export default {
|
||||
cssPath: './assets/css/tailwind.css',
|
||||
configPath: 'tailwind.config.js',
|
||||
exposeConfig: true
|
||||
}
|
||||
@@ -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',
|
||||
},
|
||||
}
|
||||
@@ -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 }
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
@@ -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
@@ -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)
|
||||
36
package.json
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
272
pages/about.vue
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
117
pages/index.vue
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
@@ -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
@@ -0,0 +1,4 @@
|
||||
// Build Configuration: https://go.nuxtjs.dev/config-build
|
||||
export default {
|
||||
|
||||
}
|
||||
47
settings/BuildModules.ts
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 185 KiB |
BIN
src/assets/images/logo-header.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
src/assets/images/memojies/Dev.png
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
src/assets/images/memojies/Fiesta.png
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
src/assets/images/memojies/Hey.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 457 KiB After Width: | Height: | Size: 457 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
1
src/assets/images/socials/github-black.svg
Normal 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 |
5
src/assets/images/socials/github-white.svg
Normal 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 |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 573 B After Width: | Height: | Size: 573 B |
|
Before Width: | Height: | Size: 702 B After Width: | Height: | Size: 702 B |
43
src/components/AboutHome.vue
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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>
|
||||
91
src/components/ContactForm.vue
Normal 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>
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="w-full mb-10">
|
||||
<section class="w-full mb-10">
|
||||
<slot />
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
78
src/components/Experience.vue
Normal 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>
|
||||
44
src/components/ExperiencesAbout.vue
Normal 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>
|
||||
@@ -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>
|
||||
73
src/components/Formation.vue
Normal 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>
|
||||
44
src/components/FormationsAbout.vue
Normal 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>
|
||||