mirror of
https://github.com/ArthurDanjou/website-old.git
synced 2026-01-14 12:14:42 +01:00
💻 | Working so hard on the design review
This commit is contained in:
11
@types/index.d.ts
vendored
11
@types/index.d.ts
vendored
@@ -1,28 +1,33 @@
|
||||
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";
|
||||
|
||||
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
|
||||
i18n: VueI18n & IVueI18n
|
||||
$colorMode: ColorModeInstance,
|
||||
$app: NuxtApp
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'vuex/types/index' {
|
||||
interface Store<S> {
|
||||
$axios: NuxtAxiosInstance
|
||||
$axios: NuxtAxiosInstance,
|
||||
i18n: VueI18n & IVueI18n
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,5 +36,28 @@ interface Formation {
|
||||
end_date: string
|
||||
}
|
||||
|
||||
interface Tag {
|
||||
slug: string
|
||||
}
|
||||
|
||||
export { FormData, InfoData, Skill, Experience, Formation }
|
||||
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 { FormData, InfoData, Skill, Experience, Formation, Post, Tag, Project }
|
||||
|
||||
70
docker-compose.yml
Normal file
70
docker-compose.yml
Normal file
@@ -0,0 +1,70 @@
|
||||
version: "3"
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
name: proxy
|
||||
external: true
|
||||
internal:
|
||||
name: internal
|
||||
external: false
|
||||
|
||||
services:
|
||||
artsite:
|
||||
image: artsite:latest
|
||||
container_name: artsite
|
||||
labels:
|
||||
- traefik.http.routers.artsite.rule=Host(`arthurdanjou.fr`)
|
||||
- traefik.http.routers.artsite.tls=true
|
||||
- traefik.http.routers.artsite.tls.certresolver=lets-encrypt
|
||||
- traefik.docker.network=proxy
|
||||
- traefik.port=443
|
||||
ports:
|
||||
- 3333:3333
|
||||
networks:
|
||||
- internal
|
||||
- proxy
|
||||
depends_on:
|
||||
- artapi
|
||||
artapi:
|
||||
image: artapi:latest
|
||||
container_name: artapi
|
||||
labels:
|
||||
- traefik.http.routers.artapi.rule=Host(`api.arthurdanjou.fr`)
|
||||
- traefik.http.routers.artapi.tls=true
|
||||
- traefik.http.routers.artapi.tls.certresolver=lets-encrypt
|
||||
- traefik.docker.network=proxy
|
||||
- traefik.port=443
|
||||
ports:
|
||||
- 5555:5555
|
||||
networks:
|
||||
- internal
|
||||
- proxy
|
||||
depends_on:
|
||||
- mariadb
|
||||
- redis
|
||||
mariadb:
|
||||
image: mariadb:10.5.8-focal
|
||||
container_name: mariadb
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD:
|
||||
ports:
|
||||
- 3306:3306
|
||||
networks:
|
||||
- internal
|
||||
- proxy
|
||||
labels:
|
||||
- traefik.tcp.routers.sql.entrypoints=sql
|
||||
- traefik.tcp.routers.sql.rule=HostSNI(`sql.arthurdanjou.fr`)
|
||||
- traefik.docker.network=proxy
|
||||
volumes:
|
||||
- "/root/mariadb/data:/var/lib/mysql"
|
||||
redis:
|
||||
image: redis:6.0.10
|
||||
container_name: redis
|
||||
command: redis-server
|
||||
ports:
|
||||
- 6379:6379
|
||||
networks:
|
||||
- internal
|
||||
volumes:
|
||||
- "/root/redis/data:/data"
|
||||
30
package.json
30
package.json
@@ -9,24 +9,24 @@
|
||||
"generate": "nuxt generate"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/content": "^1.11.1",
|
||||
"@nuxtjs/axios": "^5.12.5",
|
||||
"@nuxtjs/composition-api": "^0.22.2",
|
||||
"core-js": "^3.9.1",
|
||||
"nuxt": "2.15.3",
|
||||
"nuxt-i18n": "6.21.1",
|
||||
"prism-themes": "1.6.0",
|
||||
"sass": "1.32.8"
|
||||
"@nuxt/content": "^1.14.0",
|
||||
"@nuxtjs/axios": "^5.13.1",
|
||||
"@nuxtjs/composition-api": "^0.22.4",
|
||||
"core-js": "^3.10.0",
|
||||
"nuxt": "^2.15.3",
|
||||
"nuxt-i18n": "^6.22.3",
|
||||
"prism-themes": "^1.6.0",
|
||||
"sass": "^1.32.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/types": "^2.14.12",
|
||||
"@nuxt/typescript-build": "^2.0.4",
|
||||
"@nuxtjs/color-mode": "2.0.5",
|
||||
"node-sass": "^5.0.0",
|
||||
"@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.4.6",
|
||||
"sass-loader": "10.1.1",
|
||||
"vite-plugin-windicss": "^0.11.2",
|
||||
"nuxt-windicss": "^0.5.3",
|
||||
"sass-loader": "^10.1.1",
|
||||
"vite-plugin-windicss": "^0.11.3",
|
||||
"vue-windicss-preprocess": "^2.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,6 @@ const build = {
|
||||
extractCss: true,
|
||||
}
|
||||
|
||||
const generate = {
|
||||
interval: 2000,
|
||||
}
|
||||
|
||||
const pageTransition = {
|
||||
name: 'page',
|
||||
mode: 'out-in',
|
||||
@@ -32,4 +28,6 @@ const components = true
|
||||
|
||||
const buildDir = 'build'
|
||||
|
||||
export default { srcDir, dir, generate, build, pageTransition, target, server, buildDir, components }
|
||||
const ssr = true
|
||||
|
||||
export default { srcDir, dir, build, pageTransition, target, server, buildDir, components, ssr }
|
||||
|
||||
@@ -1,15 +1,4 @@
|
||||
// Build Configuration: https://go.nuxtjs.dev/config-build
|
||||
export default {
|
||||
extend(config: any) {
|
||||
config.module.rules.push({
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-windicss-preprocess',
|
||||
options: {
|
||||
compile: true, // false: interpretation mode; true: compilation mode
|
||||
globalPreflight: true, // set preflight style is global or scoped
|
||||
globalUtility: true, // set utility style is global or scoped
|
||||
prefix: 'windi-' // set compilation mode style prefix
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ const windicss = {
|
||||
],
|
||||
include: []
|
||||
},
|
||||
transformCSS: 'post',
|
||||
transformCSS: 'pre',
|
||||
preflight: {
|
||||
alias: {
|
||||
// add nuxt aliases
|
||||
@@ -32,10 +32,16 @@ const windicss = {
|
||||
}
|
||||
}
|
||||
|
||||
const vite = {
|
||||
vue: {
|
||||
jsx: false
|
||||
}
|
||||
}
|
||||
|
||||
export default [
|
||||
'@nuxt/typescript-build',
|
||||
'@nuxtjs/composition-api',
|
||||
['nuxt-windicss', windicss],
|
||||
'nuxt-vite',
|
||||
//['nuxt-vite', vite],
|
||||
['@nuxtjs/color-mode', color_mode],
|
||||
] as NuxtOptionsModule[]
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
|
||||
export default []
|
||||
export default [
|
||||
{ src: '~/plugins/i18n.ts' }
|
||||
]
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
// Global CSS: https://go.nuxtjs.dev/config-css
|
||||
export default []
|
||||
export default [
|
||||
'@/assets/css/style.scss'
|
||||
]
|
||||
|
||||
@@ -10,7 +10,7 @@ img, svg {
|
||||
}
|
||||
|
||||
body {
|
||||
@apply dark:bg-dark-900
|
||||
@apply dark:bg-black dark:text-white
|
||||
}
|
||||
|
||||
* {
|
||||
|
||||
43
src/components/AboutPreview.vue
Normal file
43
src/components/AboutPreview.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 justify-between items-center">
|
||||
<div class="w-1/2 flex justify-center">
|
||||
<img src="@/assets/images/Logo.jpg" alt="Logo Image" class="w-1/2 rounded-2xl border-2 border-gray-100 dark:border-transparent">
|
||||
</div>
|
||||
<div class="w-1/2 text-justify">
|
||||
<h2 class="text-4xl font-bold">
|
||||
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">
|
||||
<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>
|
||||
41
src/components/Ad.vue
Normal file
41
src/components/Ad.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<div class="rounded-3xl p-12 text-center shadow-md" :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'
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
getColor
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
46
src/components/AdPreview.vue
Normal file
46
src/components/AdPreview.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<div class="w-full my-12">
|
||||
<div class="space-x-12 flex items-center justify-center">
|
||||
<nuxt-link to="/uses" class="h-84 w-1/2">
|
||||
<Ad class="h-full w-full flex flex-col justify-between">
|
||||
<div>
|
||||
ILLUSTRATION
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="font-bold text-black text-3xl">
|
||||
Usages
|
||||
</h1>
|
||||
<p class="text-lg text-gray-700 mt-4">
|
||||
Venez decouvrir mon environnement de developpement
|
||||
</p>
|
||||
</div>
|
||||
</Ad>
|
||||
</nuxt-link>
|
||||
<nuxt-link to="/contact" class="h-84 w-1/2">
|
||||
<Ad color="blue" class="h-full w-full flex flex-col justify-between">
|
||||
<div>
|
||||
ILLUSTRATION
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="font-bold text-black text-4xl">
|
||||
Vous avez un projet ?
|
||||
</h1>
|
||||
<p class="text-lg text-gray-700 mt-4">
|
||||
Contactez moi en detaillant votre projet pour debuter notre collaboration.
|
||||
</p>
|
||||
</div>
|
||||
</Ad>
|
||||
</nuxt-link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "AdPreview"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
29
src/components/Banner.vue
Normal file
29
src/components/Banner.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<section class="my-32 w-full flex items-center justify-center">
|
||||
<div class="text-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>
|
||||
<h3 class="my-6 text-2xl font-medium text-gray-700 dark:text-gray-400">
|
||||
Developer and Student
|
||||
</h3>
|
||||
<p class="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-teal-400 hover:border-teal-400 duration-200 dark:(font-white border-gray-700) hover:dark:border-teal-400
|
||||
}
|
||||
</style>
|
||||
27
src/components/Button.vue
Normal file
27
src/components/Button.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<nuxt-link :to="link">
|
||||
<div class="text-lg cursor-pointer px-8 py-4 rounded-xl border-2 border-gray-600 hover:(bg-gray-700 text-white) text-gray-700 duration-300 dark:(border-gray-400 text-gray-400) dark:hover:bg-gray-400 dark:hover:text-black">
|
||||
{{ 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>
|
||||
@@ -51,14 +51,14 @@ export default {
|
||||
}
|
||||
},
|
||||
setup(props: ExperienceProps) {
|
||||
const {$i18n} = useContext()
|
||||
const {i18n} = useContext()
|
||||
const getBeginDate = computed(() => {
|
||||
const dateFormat = props.begin.split('-')
|
||||
return $i18n.t('month.' + dateFormat[0]) + " " + dateFormat[1]
|
||||
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 props.end === 'Today' ? i18n.t('date.today') : i18n.t('month.' + dateFormat[0]) + " " + dateFormat[1]
|
||||
})
|
||||
|
||||
const isSameDate = () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<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">
|
||||
@@ -67,7 +67,7 @@ export default {
|
||||
}
|
||||
|
||||
.link {
|
||||
@apply duration-300;
|
||||
@apply duration-100;
|
||||
|
||||
&: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;
|
||||
|
||||
@@ -50,18 +50,14 @@ export default {
|
||||
}
|
||||
},
|
||||
setup(props: FormationProps) {
|
||||
const {$i18n} = useContext()
|
||||
const {i18n} = useContext()
|
||||
const getBeginDate = computed(() => {
|
||||
const dateFormat = props.begin.split('-')
|
||||
console.log('1')
|
||||
console.log($i18n.t('month.' + dateFormat[0]) + " " + dateFormat[1])
|
||||
return $i18n.t('month.' + dateFormat[0]) + " " + dateFormat[1]
|
||||
return i18n.t('month.' + dateFormat[0]) + " " + dateFormat[1]
|
||||
})
|
||||
const getEndDate = computed(() => {
|
||||
const dateFormat = props.end.split('-')
|
||||
console.log('2')
|
||||
console.log(props.end === 'Today' ? $i18n.t('date.today') : $i18n.t('month.' + dateFormat[0]) + " " + dateFormat[1])
|
||||
return props.end === 'Today' ? $i18n.t('date.today') : $i18n.t('month.' + dateFormat[0]) + " " + dateFormat[1]
|
||||
return props.end === 'Today' ? i18n.t('date.today') : i18n.t('month.' + dateFormat[0]) + " " + dateFormat[1]
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<header class="dark:bg-black dark:text-white fixed z-50 top-0 left-0 bg-white header w-full h-16 lg:h-24 duration-500" :class="scrollPosition > 50 ? ' shadow-md dark:shadow-white' : ''">
|
||||
<header class="dark:bg-black dark:text-white fixed z-50 top-0 left-0 bg-white w-full duration-400" :class="scrollPosition > 50 ? ' shadow-md dark:shadow-white h-10 lg:h-18' : 'h-16 lg:h-24'">
|
||||
<div class="header-container z-index-50 flex justify-between items-center h-full px-5 xl:px-32">
|
||||
<nuxt-link to="/">
|
||||
<img src="@/assets/images/logo-header.png" alt="Logo Circle" class="h-10 left cursor-pointer duration-500" />
|
||||
@@ -80,11 +80,11 @@
|
||||
</nav>
|
||||
<div>
|
||||
<ul class="flex items-center">
|
||||
<li class="mx-1 h-9 w-9 cursor-pointer flex items-center justify-center p-1.5 rounded-xl hover:bg-gray-300 duration-200 dark:hover:bg-dark-850">
|
||||
<div v-if="this.$i18n.locale === 'en'" @click="changeLanguage('fr')">
|
||||
:fr:
|
||||
<li @click="changeLanguage()" class="mx-1 h-9 w-9 cursor-pointer flex items-center justify-center p-1.5 rounded-xl hover:bg-gray-300 duration-200 dark:hover:bg-dark-850">
|
||||
<div v-if="this.$i18n.locale === 'en'">
|
||||
Fr
|
||||
</div>
|
||||
<div v-else @click="changeLanguage('en')">
|
||||
<div v-else>
|
||||
🇬🇧
|
||||
</div>
|
||||
</li>
|
||||
@@ -114,7 +114,6 @@ export default {
|
||||
setup() {
|
||||
const {$colorMode} = useContext()
|
||||
const changeColorMode = () => {
|
||||
console.log("changed !")
|
||||
$colorMode.preference = $colorMode.value === 'light' ? 'dark' : 'light'
|
||||
}
|
||||
|
||||
@@ -131,13 +130,12 @@ export default {
|
||||
window.removeEventListener('scroll', updateScroll)
|
||||
})
|
||||
|
||||
const {app, $i18n} = useContext()
|
||||
const {i18n} = useContext()
|
||||
const $router = useRouter()
|
||||
const changeLanguage = (lang: 'fr' | 'en') => useAsync(() => {
|
||||
console.log("i18n changed")
|
||||
$i18n.setLocale(lang)
|
||||
if ($router.currentRoute.fullPath.includes('blog')) {
|
||||
app.refresh()
|
||||
const changeLanguage = () => useAsync(() => {
|
||||
i18n.setLocale(i18n.locale === 'fr' ? 'en' : 'fr')
|
||||
if ($router.currentRoute.fullPath.includes('blog') || $router.currentRoute.fullPath === '/') {
|
||||
window.location.reload()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -152,25 +150,19 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.header {
|
||||
.nav-link {
|
||||
@apply text-gray-500 dark:text-gray-400 hover:dark:text-white font-medium hover:text-black mx-4 cursor-pointer duration-300
|
||||
}
|
||||
|
||||
.header-container {
|
||||
.nav-link-mobile {
|
||||
@apply text-gray-500 dark:text-gray-400 hover:dark:text-white hover:text-black duration-300
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
@apply text-gray-500 dark:text-gray-400 hover:dark:text-white font-medium hover:text-black mx-4 cursor-pointer duration-300
|
||||
}
|
||||
nav .nuxt-link-exact-active {
|
||||
@apply text-black dark:text-white;
|
||||
}
|
||||
|
||||
.nav-link-mobile {
|
||||
@apply text-gray-500 dark:text-gray-400 hover:dark:text-white hover:text-black duration-300
|
||||
}
|
||||
|
||||
nav .nuxt-link-exact-active {
|
||||
@apply text-black dark:text-white;
|
||||
}
|
||||
|
||||
.navbar-bottom-items li {
|
||||
transition: all .2s ease-in-out;
|
||||
}
|
||||
}
|
||||
.navbar-bottom-items li {
|
||||
transition: all .2s ease-in-out;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,87 +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 lang="ts">
|
||||
|
||||
import {computed} from "@nuxtjs/composition-api";
|
||||
|
||||
interface HomeLinkProps {
|
||||
title: string,
|
||||
description: string,
|
||||
color: string,
|
||||
link: string
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "HomeLink",
|
||||
props: {
|
||||
title: {
|
||||
default: "Title",
|
||||
type: String
|
||||
},
|
||||
description: {
|
||||
default: "Description",
|
||||
type: String
|
||||
},
|
||||
color: {
|
||||
default: "red",
|
||||
type: String
|
||||
},
|
||||
link: {
|
||||
default: "/",
|
||||
type: String
|
||||
}
|
||||
},
|
||||
setup(props: HomeLinkProps) {
|
||||
/**const getColor = computed(() => {
|
||||
return 'hover:bg-color-400 dark:hover:bg-color-600 active:bg-color-400 dark:active:bg-color-600'.replaceAll('color', props.color)
|
||||
})*/
|
||||
const getColor = computed(() => {
|
||||
switch (props.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'
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
getColor,
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.home-link:hover {
|
||||
p {
|
||||
@apply dark:text-white
|
||||
}
|
||||
.arrow {
|
||||
transform: translateX(15px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,6 @@
|
||||
<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"
|
||||
class="mt-16 md:mt-32 font-bold text-2xl md:text-4xl mr-2 inline mb-4 border-b-2 border-solid border-gray-200 dark:border-gray-800"
|
||||
>
|
||||
{{ this.$t(title) }}
|
||||
<slot />
|
||||
@@ -9,31 +8,12 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import {computed} from "@nuxtjs/composition-api";
|
||||
|
||||
interface TitleProps {
|
||||
title: string,
|
||||
color: string
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "PageTitle",
|
||||
props: {
|
||||
title: {
|
||||
default: 'Title',
|
||||
type: String
|
||||
},
|
||||
color: {
|
||||
default: 'red',
|
||||
type: String
|
||||
}
|
||||
},
|
||||
setup(props: TitleProps) {
|
||||
const getColor = computed(() => `border-${props.color}-400`)
|
||||
|
||||
return {
|
||||
getColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,104 +1,85 @@
|
||||
<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(${getBackGroundCover})` }"
|
||||
>
|
||||
<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>{{getDate}}</div>
|
||||
<div>{{reading_time}} min</div>
|
||||
<nuxt-link :to="`/blog/${slug}`">
|
||||
<div class="rounded-lg shadow-lg h-116 w-100 text-left dark:bg-gray-800 transform hover:scale-103 duration-300">
|
||||
<div class="h-2/5 post rounded-t-lg"
|
||||
:style="{ backgroundImage: `url(${getBackgroundCover})` }">
|
||||
</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 class="h-3/5 p-4 flex flex-col justify-between">
|
||||
<div>
|
||||
<div class="flex space-x-2 mb-2">
|
||||
<div v-for="tag in tags">
|
||||
<TagPreview :content="tag" :pill="true"/>
|
||||
</div>
|
||||
</div>
|
||||
<h1 class="text-2xl font-bold">{{ title }}</h1>
|
||||
<p class="text-base mt-3 text-gray-700 dark:text-gray-400 text-justify">{{ description }}</p>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<h5 class="text-base text-gray-700 dark:text-gray-400">{{ date }}</h5>
|
||||
<h5 class="text-base text-gray-700 dark:text-gray-400">{{ reading_time }} min.</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</nuxt-link>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {computed, useContext} from "@nuxtjs/composition-api";
|
||||
import {computed} from "@nuxtjs/composition-api";
|
||||
|
||||
interface PostProps {
|
||||
interface PostHomeProps {
|
||||
title: string,
|
||||
description: string,
|
||||
reading_time: number,
|
||||
date: string,
|
||||
tags: [],
|
||||
cover: string,
|
||||
background_is_light: boolean
|
||||
slug: string,
|
||||
tags: Array<string>,
|
||||
reading_time: number
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "Post",
|
||||
name: "PostHome",
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: "New Post's title "
|
||||
default: "Title"
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
default: "New Post's description"
|
||||
},
|
||||
reading_time: {
|
||||
type: Number,
|
||||
default: 0
|
||||
default: "Description"
|
||||
},
|
||||
date: {
|
||||
type: String,
|
||||
default: "Today"
|
||||
default: "Date"
|
||||
},
|
||||
cover: {
|
||||
type: String,
|
||||
default: "string"
|
||||
},
|
||||
slug: {
|
||||
type: String,
|
||||
default: "slug"
|
||||
},
|
||||
tags: {
|
||||
type: Array,
|
||||
default: () => ["Tag1", "Tag2", "Tag3"],
|
||||
},
|
||||
cover: {
|
||||
type: String,
|
||||
default: "default.png"
|
||||
reading_time: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
lightBg: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
setup(props: PostProps) {
|
||||
const {$i18n} = useContext()
|
||||
|
||||
const getDate = computed(() => {
|
||||
const dateFormat = props.date.split('-')
|
||||
return dateFormat[0] + " " + $i18n.t('month.' + dateFormat[1]) + " " + dateFormat[2]
|
||||
})
|
||||
|
||||
const getBackGroundCover = computed(() => require(`~/assets/images/posts/${props.cover}.png`))
|
||||
setup(props: PostHomeProps) {
|
||||
const getBackgroundCover = computed(() => require(`@/assets/images/posts/${props.cover}`))
|
||||
|
||||
return {
|
||||
getDate,
|
||||
getBackGroundCover
|
||||
getBackgroundCover
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.h-blog {
|
||||
min-height: 20rem;
|
||||
.post {
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
@apply bg-opacity-50;
|
||||
|
||||
57
src/components/PostsPreview.vue
Normal file
57
src/components/PostsPreview.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<section v-if="posts" class="w-full flex items-center justify-center my-20">
|
||||
<div class="flex flex-col items-center text-center">
|
||||
<div class="flex flex-col items-center">
|
||||
<h2 class="font-bold text-3xl">
|
||||
Derniers articles
|
||||
</h2>
|
||||
<p class="text-gray-700 dark:text-gray-400 text-xl w-2/3 mt-4">
|
||||
Je redige des articles concernant ma vie, le developpement et mes passions.
|
||||
</p>
|
||||
</div>
|
||||
<div class="my-8 flex w-full space-x-6">
|
||||
<div v-for="post in posts">
|
||||
<Post
|
||||
:title="post.title"
|
||||
:cover="post.cover"
|
||||
:description="post.description"
|
||||
:date="post.date"
|
||||
:slug="post.slug"
|
||||
:tags="post.tags"
|
||||
:reading_time="post.reading_time"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<Button content="Voir plus d'articles" link="blog"/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {useAsync, useContext} from "@nuxtjs/composition-api";
|
||||
import {Post} from "../../@types/types";
|
||||
|
||||
export default {
|
||||
name: "PostsPreview",
|
||||
setup() {
|
||||
const { $content, i18n } = useContext()
|
||||
|
||||
const posts = useAsync(() => {
|
||||
return $content(`articles/${i18n.locale}`)
|
||||
.sortBy("date", "asc")
|
||||
.limit(3)
|
||||
.fetch<Post>()
|
||||
})
|
||||
|
||||
return {
|
||||
posts
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
74
src/components/Project.vue
Normal file
74
src/components/Project.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<nuxt-link :to="`/projects/${slug}`">
|
||||
<div class="rounded-lg shadow-lg w-72 text-left dark:bg-gray-800 transform hover:scale-103 duration-300">
|
||||
<div class="h-40 post rounded-t-lg"
|
||||
:style="{ backgroundImage: `url(${getBackgroundCover})` }">
|
||||
</div>
|
||||
<div class="p-4 flex flex-col justify-between">
|
||||
<h1 class="text-xl font-bold">
|
||||
{{ title }}
|
||||
</h1>
|
||||
<div class="flex space-x-2 mt-2">
|
||||
<div v-for="tag in tags">
|
||||
<TagPreview :content="tag" :pill="false"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nuxt-link>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import {computed} from "@nuxtjs/composition-api";
|
||||
|
||||
interface ProjectProp {
|
||||
title: string,
|
||||
description: string,
|
||||
cover: string,
|
||||
slug: string,
|
||||
color: string,
|
||||
url: string
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "Project",
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: "Title"
|
||||
},
|
||||
cover: {
|
||||
type: String,
|
||||
default: "artapi.png"
|
||||
},
|
||||
slug: {
|
||||
type: String,
|
||||
default: "slug"
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: "red"
|
||||
},
|
||||
tags: {
|
||||
type: Array,
|
||||
default: () => ['tags.web', 'tags.software']
|
||||
}
|
||||
},
|
||||
setup(props: ProjectProp) {
|
||||
const getBackgroundCover = computed(() => require(`@/assets/images/works/artapi.png`))
|
||||
|
||||
return {
|
||||
getBackgroundCover
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.project {
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
@apply bg-opacity-50;
|
||||
}
|
||||
</style>
|
||||
53
src/components/ProjectsPreview.vue
Normal file
53
src/components/ProjectsPreview.vue
Normal file
@@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<section v-if="projects" class="w-full flex items-center justify-center my-20">
|
||||
<div class="flex flex-col items-center text-center">
|
||||
<div class="flex flex-col items-center">
|
||||
<h2 class="font-bold text-3xl">
|
||||
Derniers projets
|
||||
</h2>
|
||||
<p class="text-gray-700 dark:text-gray-400 text-xl w-2/3 mt-4">
|
||||
Quelques projets que j'ai realise dans ma vie de developpeur.
|
||||
</p>
|
||||
</div>
|
||||
<div class="my-8 flex w-full space-x-8">
|
||||
<div v-for="project in projects">
|
||||
<Project
|
||||
:title="project.title"
|
||||
:description="project.description"
|
||||
:color="project.color"
|
||||
:cover="project.cover"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<Button content="Voir plus de projets" link="projects"/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {useAsync, useContext} from "@nuxtjs/composition-api";
|
||||
import {Project} from "../../@types/types";
|
||||
|
||||
export default {
|
||||
name: "ProjectsPreview",
|
||||
setup() {
|
||||
const { $content } = useContext()
|
||||
|
||||
const projects = useAsync(() => {
|
||||
return $content(`projects`)
|
||||
.limit(3)
|
||||
.fetch<Project>()
|
||||
})
|
||||
|
||||
return {
|
||||
projects
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -35,7 +35,34 @@ export default {
|
||||
}
|
||||
},
|
||||
setup(props: SkillProps) {
|
||||
const getColor = computed(() => `hover:bg-${props.color}-400`)
|
||||
const getColor = computed(() => {
|
||||
switch (props.color) {
|
||||
case 'blueGray':
|
||||
return 'hover:bg-blueGray-400'
|
||||
case 'cyan':
|
||||
return 'hover:bg-cyan-400'
|
||||
case 'yellow':
|
||||
return 'hover:bg-yellow-400'
|
||||
case 'emerald':
|
||||
return 'hover:bg-emerald-400'
|
||||
case 'black':
|
||||
return 'hover:bg-black dark:hover:bg-gray-500'
|
||||
case 'orange':
|
||||
return 'hover:bg-orange-400'
|
||||
case 'lightBlue':
|
||||
return 'hover:bg-lightBlue-400'
|
||||
case 'lime':
|
||||
return 'hover:bg-lime-400'
|
||||
case 'teal':
|
||||
return 'hover:bg-teal-400'
|
||||
case 'blue':
|
||||
return 'hover:bg-blue-400'
|
||||
case 'red':
|
||||
return 'hover:bg-red-400'
|
||||
case 'rose':
|
||||
return 'hover:bg-rose-400'
|
||||
}
|
||||
})
|
||||
const getCoverLink = computed(() => require(`@/assets/images/skills/${props.cover}.png`))
|
||||
|
||||
return {
|
||||
|
||||
38
src/components/StrategyPart.vue
Normal file
38
src/components/StrategyPart.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1 class="font-bold text-2xl">
|
||||
{{ title }}
|
||||
</h1>
|
||||
<p class="text-gray-700 dark:text-gray-400 text-base text-justify">
|
||||
{{ description }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
interface StrategyPartProp {
|
||||
title: string,
|
||||
description: string
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "StrategyPart",
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: 'Title'
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
default: 'Description'
|
||||
}
|
||||
},
|
||||
setup(props: StrategyPartProp) {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
49
src/components/StrategyPreview.vue
Normal file
49
src/components/StrategyPreview.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<section class="w-full flex items-center justify-center my-12">
|
||||
<div class="flex flex-col items-center w-full">
|
||||
<div class="flex flex-col items-center">
|
||||
<h2 class="font-bold text-3xl">
|
||||
Workflow
|
||||
</h2>
|
||||
<p class="text-gray-700 dark:text-gray-400 text-xl w-2/3 mt-4">
|
||||
Je suis ce processus afin d'etre le plus productif et de donner le resultat le plus qualitatif possible.
|
||||
</p>
|
||||
</div>
|
||||
<div class="my-8 flex flex-row-reverse w-full justify-between items-center">
|
||||
<div class="w-1/2 flex justify-center items-center">
|
||||
La belle image
|
||||
</div>
|
||||
<div class="flex justify-center 1/2">
|
||||
<div class="flex flex-col space-y-6 w-full">
|
||||
<StrategyPart
|
||||
title="#1. Brainstorming"
|
||||
description="Je realise blablabla Je realise blablabla Je realise blablabla Je realise blablabla"
|
||||
/>
|
||||
<StrategyPart
|
||||
title="#2. Conception"
|
||||
description="Je realise blablabla"
|
||||
/>
|
||||
<StrategyPart
|
||||
title="#3. Developpement"
|
||||
description="Je realise blablabla"
|
||||
/>
|
||||
<StrategyPart
|
||||
title="#4. Livraison"
|
||||
description="Je realise blablabla"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "StrategyPreview",
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
28
src/components/TagPreview.vue
Normal file
28
src/components/TagPreview.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<div
|
||||
class="px-2 py-0.5 rounded-full bg-gray-200 text-sm text-gray-800 dark:(bg-gray-700 text-gray-300)"
|
||||
:class="pill === true ? 'px-2 py-0.5 rounded-full' : 'px-2 py-1 rounded-md'"
|
||||
>
|
||||
{{ $t(content) }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "TagPreview",
|
||||
props: {
|
||||
content: {
|
||||
type: String,
|
||||
default: "Content"
|
||||
},
|
||||
pill: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -4,7 +4,7 @@ title: How did I start development?
|
||||
description: How did I start development? What am I capable of mastering? What will my future be?
|
||||
reading_time: 5
|
||||
tags: ["tags.life"]
|
||||
cover: post-2
|
||||
cover: post-2.png
|
||||
date: 07-01-2021
|
||||
background: true
|
||||
---
|
||||
|
||||
@@ -4,7 +4,7 @@ title: Opening of the new version of my site!
|
||||
description: After long months of development, here is version 2 of my site!
|
||||
reading_time: 2
|
||||
tags: ["tags.dev"]
|
||||
cover: post-1
|
||||
cover: post-1.png
|
||||
date: 13-12-2020
|
||||
background: false
|
||||
---
|
||||
|
||||
@@ -4,7 +4,7 @@ title: Comment ai-je commencé le développement ?
|
||||
description: Comment ai-je commencé le développement ? Que suis-je capable de maitriser ? Quel sera mon futur ?
|
||||
reading_time: 5
|
||||
tags: ["tags.life"]
|
||||
cover: post-2
|
||||
cover: post-2.png
|
||||
date: 07-01-2021
|
||||
background: false
|
||||
---
|
||||
|
||||
@@ -4,9 +4,8 @@ title: Ouverture de la nouvelle version de mon site !
|
||||
description: Après de long mois de développement, voici la version 2 de mon site !
|
||||
reading_time: 2
|
||||
tags: ["tags.dev"]
|
||||
cover: post-1
|
||||
cover: post-1.png
|
||||
date: 13-12-2020
|
||||
background: false
|
||||
---
|
||||
|
||||
## Présentation
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"title": "Erisium",
|
||||
"description": "works.erisium",
|
||||
"url": "https://erisium.com",
|
||||
"cover": "erisium",
|
||||
"cover": "erisium.png",
|
||||
"color": "fuchsia",
|
||||
"skills": [
|
||||
"java",
|
||||
@@ -18,7 +18,7 @@
|
||||
"title": "ArtSite",
|
||||
"description": "works.artsite",
|
||||
"url": "https://arthurdanjou.fr",
|
||||
"cover": "artsite",
|
||||
"cover": "artsite.png",
|
||||
"color": "trueGray",
|
||||
"skills": [
|
||||
"typescript",
|
||||
@@ -37,7 +37,7 @@
|
||||
"title": "ArtApi",
|
||||
"description": "works.artapi",
|
||||
"url": "https://api.arthurdanjou.fr",
|
||||
"cover": "artapi",
|
||||
"cover": "artapi.png",
|
||||
"color": "trueGray",
|
||||
"skills": [
|
||||
"typescript",
|
||||
@@ -54,7 +54,7 @@
|
||||
"title": "ArtClick",
|
||||
"description": "works.artclick",
|
||||
"url": "https://artdanj.to",
|
||||
"cover": "artclick",
|
||||
"cover": "artclick.png",
|
||||
"color": "trueGray",
|
||||
"skills": [
|
||||
"adonisjs",
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="dark:bg-dark-900 dark:text-white font-sans">
|
||||
<div>
|
||||
<Header />
|
||||
<Nuxt class="z-10 pt-16 lg:pt-24 content" />
|
||||
<Nuxt class="z-10 pt-16 lg:pt-24 content px-5 xl:px-32"/>
|
||||
<Footer />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<template>
|
||||
<Nuxt />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "dev"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,8 +1,8 @@
|
||||
export default {
|
||||
header: {
|
||||
home: 'Home',
|
||||
about: 'About',
|
||||
blog: 'Blog',
|
||||
contact: 'Contact',
|
||||
projects: 'Projects',
|
||||
uses: 'Uses',
|
||||
},
|
||||
@@ -192,7 +192,9 @@ export default {
|
||||
tags: {
|
||||
life: 'Life',
|
||||
dev: 'Dev',
|
||||
tech: 'Tech'
|
||||
tech: 'Tech',
|
||||
software: 'Software',
|
||||
web: 'Web'
|
||||
},
|
||||
|
||||
experiences: {
|
||||
|
||||
@@ -192,7 +192,9 @@ export default {
|
||||
tags: {
|
||||
life: 'Vie',
|
||||
dev: 'Dev',
|
||||
tech: 'Tech'
|
||||
tech: 'Tech',
|
||||
software: 'Logiciel',
|
||||
web: 'Web'
|
||||
},
|
||||
|
||||
experiences: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<main class="about flex flex-col items-center px-5 xl:px-64">
|
||||
<main class="about flex flex-col items-center">
|
||||
<PageTitle
|
||||
title="part.about"
|
||||
color="orange"
|
||||
@@ -143,7 +143,7 @@
|
||||
:end="experience.end_date" />
|
||||
</div>
|
||||
</div>
|
||||
<nuxt-link to="/cv">
|
||||
<nuxt-link to="/cv" class="mb-12">
|
||||
<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">
|
||||
@@ -151,80 +151,6 @@
|
||||
</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>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<main class="blog flex flex-col items-center px-5 xl:px-96 mb-16 md:mb-32">
|
||||
<main v-if="post" class="blog flex flex-col items-center px-5 xl:px-96 mb-16 md:mb-32">
|
||||
<div class="mt-8 md:mt-32 flex flex-col justify-around py-8 w-full">
|
||||
<div>
|
||||
<div class="mb-4 flex">
|
||||
@@ -37,7 +37,7 @@
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<div class="flex justify-center w-full h-auto">
|
||||
<img class="w-full h-auto" :src="require(`@/assets/images/posts/${post.cover}.png`)" alt="Cover Img" />
|
||||
<img class="w-full h-auto" :src="require(`@/assets/images/posts/${post.cover}`)" alt="Cover Img" />
|
||||
</div>
|
||||
</div>
|
||||
<nuxt-content
|
||||
@@ -84,7 +84,7 @@
|
||||
</svg>
|
||||
</nuxt-link>
|
||||
<div
|
||||
@click="copyToClipBoard"
|
||||
@click="copyToClipboard"
|
||||
class="h-16 end-blog cursor-pointer duration-300 text-3xl p-3 border-solid border border-gray-400 dark:border-dark-200 hover:border-dark-800 dark:hover:border-white"
|
||||
>
|
||||
<svg class="inline icon-hover" height="40" width="40" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
@@ -103,80 +103,93 @@
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import {computed, ref, useAsync, useContext, useFetch, useMeta, useRoute} from "@nuxtjs/composition-api";
|
||||
import {Post} from "../../../@types/types";
|
||||
|
||||
export default {
|
||||
name: "blog",
|
||||
head() {
|
||||
return {
|
||||
title: 'Blog - Arthur Danjou - ' + this.post.title
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
likes: 0,
|
||||
post: null,
|
||||
setup() {
|
||||
const { $content, i18n, $axios } = useContext()
|
||||
const slug = useRoute().value.params.slug
|
||||
|
||||
isCopied: false,
|
||||
liked: false
|
||||
const post = useAsync(() => {
|
||||
return $content(`articles/${i18n.locale}`, slug)
|
||||
.fetch<Post>()
|
||||
.catch(() => {
|
||||
error({ statusCode: 404, message: "Post not found" });
|
||||
})
|
||||
})
|
||||
|
||||
const likes = ref(0)
|
||||
const liked = ref(false)
|
||||
const { fetch } = useFetch(async () => {
|
||||
likes.value = await $axios.get(`https://api.arthurdanjou.fr/posts/${slug}`).data
|
||||
liked.value = await $axios.get(`https://api.arthurdanjou.fr/posts/${slug}`).data !== 0
|
||||
})
|
||||
fetch()
|
||||
|
||||
if (post.value) {
|
||||
useMeta(() => ({ title: 'Blog - Arthur Danjou - ' + post.value.title }))
|
||||
}
|
||||
},
|
||||
async asyncData({ params, $content, app, $axios, error }) {
|
||||
const post = await $content(`articles/${app.i18n.locale}`, params.slug)
|
||||
.fetch()
|
||||
.catch(() => {
|
||||
error({ statusCode: 404, message: "Post not found" });
|
||||
});
|
||||
const {data: likes} = await $axios.get(`posts/${params.slug}`)
|
||||
const liked = await $axios.get(`posts/is/${params.slug}`)
|
||||
return {
|
||||
post,
|
||||
likes,
|
||||
liked: liked.data !== 0
|
||||
|
||||
const handleLike = async () => {
|
||||
if (liked.value) {
|
||||
const {data} = await $axios.post(`https://api.arthurdanjou.fr/posts/${post.value.slug}/unlike`)
|
||||
if (data.code === 200) {
|
||||
liked.value = false
|
||||
likes.value = data.post.likes
|
||||
}
|
||||
} else {
|
||||
const {data} = await $axios.post(`https://api.arthurdanjou.fr/posts/${post.value.slug}/like`)
|
||||
if (data.code === 200) {
|
||||
liked.value = true
|
||||
likes.value = data.post.likes
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
scrollToTop() {
|
||||
|
||||
const isCopied = ref(false)
|
||||
const copyToClipboard = () => {
|
||||
navigator.clipboard.writeText('https://arthurdanjou.fr/blog/' + post.value.slug)
|
||||
isCopied.value = true
|
||||
setTimeout(() => {
|
||||
isCopied.value = false
|
||||
}, 7000)
|
||||
}
|
||||
|
||||
const scrollToTop = () => {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: "smooth"
|
||||
})
|
||||
},
|
||||
copyToClipBoard() {
|
||||
navigator.clipboard.writeText('https://arthurdanjou.fr/blog/' + this.post.slug)
|
||||
this.isCopied = true
|
||||
setTimeout(() => {
|
||||
this.isCopied = false
|
||||
}, 7000)
|
||||
},
|
||||
async handleLike() {
|
||||
if (this.liked) {
|
||||
const {data} = await this.$axios.post(`posts/${this.post.slug}/unlike`)
|
||||
if (data.code === 200) {
|
||||
this.liked = false
|
||||
this.likes = data.post.likes
|
||||
}
|
||||
} else {
|
||||
const {data} = await this.$axios.post(`posts/${this.post.slug}/like`)
|
||||
if (data.code === 200) {
|
||||
this.liked = true
|
||||
this.likes = data.post.likes
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
formatDate() {
|
||||
const dateFormat = this.post.date.split('-')
|
||||
return dateFormat[0] + " " + this.$t('month.' + dateFormat[1]) + " " + dateFormat[2]
|
||||
},
|
||||
formatTags() {
|
||||
|
||||
const formatDate = computed(() => {
|
||||
const dateFormat = post.value.date.split('-')
|
||||
return dateFormat[0] + " " + i18n.t('month.' + dateFormat[1]) + " " + dateFormat[2]
|
||||
})
|
||||
|
||||
const formatTags = computed(() => {
|
||||
let tags = ""
|
||||
this.post.tags.map(tag => {
|
||||
tags += this.$t(tag) + ", "
|
||||
post.value.tags.map(tag => {
|
||||
tags += i18n.t(tag) + ", "
|
||||
})
|
||||
return tags.substring(0, tags.length - 2)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
post,
|
||||
likes,
|
||||
liked,
|
||||
handleLike,
|
||||
isCopied,
|
||||
copyToClipboard,
|
||||
scrollToTop,
|
||||
formatDate,
|
||||
formatTags
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<main class="blog flex flex-col items-center px-5 xl:px-64">
|
||||
<main v-if="posts" class="blog flex flex-col items-center w-full">
|
||||
<PageTitle
|
||||
title="part.blog"
|
||||
color="green"
|
||||
@@ -8,269 +8,61 @@
|
||||
<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>
|
||||
<p class="text-gray-700 dark:text-gray-400 text-xl mt-4">
|
||||
Je redige des articles concernant ma vie, le developpement et mes passions.
|
||||
</p>
|
||||
<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 class="w-full" v-else>
|
||||
<div class="flex py-8 w-full flex-wrap" >
|
||||
<div class="mx-3 my-2" v-for="post in posts">
|
||||
<Post
|
||||
:title="post.title"
|
||||
:cover="post.cover"
|
||||
:description="post.description"
|
||||
:date="post.date"
|
||||
:slug="post.slug"
|
||||
:tags="post.tags"
|
||||
/>
|
||||
</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 class="flex w-full justify-center mb-8">
|
||||
<Button
|
||||
content="Voir les anciens posts"
|
||||
to="/blog/page/2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Post from "~/components/Post";
|
||||
import PageTitle from "~/components/PageTitle";
|
||||
<script lang="ts">
|
||||
import {useAsync, useContext} from "@nuxtjs/composition-api";
|
||||
import {Post} from "../../../@types/types";
|
||||
|
||||
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}`)
|
||||
setup() {
|
||||
const { $content, i18n } = useContext()
|
||||
|
||||
const posts = useAsync(() => {
|
||||
return $content(`articles/${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)
|
||||
.limit(10)
|
||||
.fetch<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,14 +0,0 @@
|
||||
<template>
|
||||
<Header />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "dev",
|
||||
layout: 'dev'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,117 +1,25 @@
|
||||
<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="mb-4 md:mb-10 lg:w-1/2 self-center">
|
||||
<h1 @click="debug" 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 v-if="info && info.age" class="text-lg md:text-2xl text-justify mb-8 leading-7 text-gray-700 dark:text-dark-200">
|
||||
{{ $t('home.banner.description', {age: info.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>
|
||||
<Banner />
|
||||
<AboutPreview />
|
||||
<PostsPreview />
|
||||
<ProjectsPreview />
|
||||
<StrategyPreview />
|
||||
<AdPreview />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import {useAsync, useContext, watch, watchEffect} from "@nuxtjs/composition-api";
|
||||
import {InfoData} from "../../@types/types";
|
||||
|
||||
export default Vue.extend({
|
||||
head() {
|
||||
return {
|
||||
title: 'Arthur Danjou - FullStack Web & Software Developer'
|
||||
}
|
||||
},
|
||||
setup() {
|
||||
const {$content} = useContext()
|
||||
const info = useAsync(() => {
|
||||
return $content('infos').fetch<InfoData>()
|
||||
})
|
||||
|
||||
return {
|
||||
info
|
||||
}
|
||||
}
|
||||
})
|
||||
</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,5 +1,79 @@
|
||||
<template>
|
||||
|
||||
<main class="about flex flex-col items-center">
|
||||
<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-gray-700 dark:text-gray-400 text-xl mt-4 mb-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>
|
||||
|
||||
7
src/plugins/i18n.ts
Normal file
7
src/plugins/i18n.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import {Context} from "@nuxt/types";
|
||||
|
||||
export default function ({ app }: Context) {
|
||||
app.i18n.onLanguageSwitched = async () => {
|
||||
await window.$nuxt.refresh()
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
const colors = require('windicss/colors')
|
||||
const typography = require('windicss/plugin/typography')
|
||||
|
||||
//export default defineConfig({
|
||||
module.exports = {
|
||||
presets: [],
|
||||
darkMode: 'class',
|
||||
|
||||
Reference in New Issue
Block a user