This commit is contained in:
2021-08-23 19:14:23 +02:00
parent 2f50ad9d55
commit cfc0ed1ea4
40 changed files with 381 additions and 234 deletions

View File

@@ -10,20 +10,20 @@
"dependencies": {
"@nuxt/content": "^1.14.0",
"@nuxtjs/axios": "^5.13.6",
"@nuxtjs/composition-api": "^0.26.0",
"@nuxtjs/composition-api": "^0.27.0",
"@nuxtjs/dotenv": "^1.4.1",
"@nuxtjs/i18n": "^7.0.2",
"@nuxtjs/proxy": "^2.1.0",
"@nuxtjs/redirect-module": "^0.3.1",
"@nuxtjs/robots": "^2.5.0",
"@nuxtjs/sentry": "^5.1.0",
"@nuxtjs/sentry": "^5.1.2",
"@nuxtjs/sitemap": "^2.4.0",
"@nuxtjs/universal-storage": "^0.5.9",
"axios": "^0.21.1",
"core-js": "^3.16.1",
"core-js": "^3.16.2",
"nuxt": "^2.15.8",
"prism-themes": "^1.8.0",
"sass": "^1.37.5"
"sass": "^1.38.0"
},
"devDependencies": {
"@nuxt/types": "^2.15.8",

View File

@@ -41,4 +41,8 @@ const proxy = {
}
}
export default { srcDir, dir, build, pageTransition, target, server, buildDir, components, ssr, proxy }
const router = {
middleware: 'maintenance'
}
export default { router, srcDir, dir, build, pageTransition, target, server, buildDir, components, ssr, proxy }

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -26,7 +26,7 @@ export default {
const {$axios, $sentry, app} = useContext()
const announce = useAsync(async () => {
const response = await $axios.get('/api/announces', {
const response = await $axios.get('/api/announce', {
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`
}

View File

@@ -31,7 +31,9 @@ export default defineComponent({
}
})
if (response.status === 200) {
return response.data.experiences
return response.data.experiences.sort((a, b) => {
return a.end_date === 'Today' ? -1 : a.end_date.split('-')[1] > b.end_date.split('-')[1] ? -1 : a.end_date.split('-')[0] > b.end_date.split('-')[0] ? 0 : 1
})
} else {
app.error({statusCode: 500})
$sentry.captureEvent(response.data)

View File

@@ -29,7 +29,7 @@
<a target="_blank" href="https://www.twitch.tv/arthurdanjou" rel="noopener noreferrer">
<TwitchIcon />
</a>
<a target="_blank" href="https://discord.gg/RQhjE5UkxD" rel="noopener noreferrer">
<a target="_blank" href="https://discord.gg/ENG6cFQhPS" rel="noopener noreferrer">
<DiscordIcon />
</a>
<a target="_blank" href="mailto:contact@arthurdanjou.fr" rel="noopener noreferrer">

View File

@@ -31,7 +31,9 @@ export default defineComponent({
}
})
if (response.status === 200) {
return response.data.formations
return response.data.formations.sort((a, b) => {
return a.end_date === 'Today' ? -1 : a.end_date.split('-')[1] > b.end_date.split('-')[1] ? -1 : a.end_date.split('-')[0] > b.end_date.split('-')[0] ? 0 : 1
})
} else {
app.error({statusCode: 500})
$sentry.captureEvent(response.data)

View File

@@ -23,7 +23,7 @@
<ul class="flex items-center">
<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-400">
<TranslateIcon/>
<TranslateIcon :french="isFrench"/>
</li>
<li @click="changeColorMode()"
class="mx-1 h-9 w-9 cursor-pointer flex items-center p-1.5 rounded-xl hover:bg-gray-300 dark:hover:bg-dark-400 duration-200">
@@ -83,6 +83,7 @@ export default defineComponent({
window.location.reload()
}
})
const isFrench = computed(() => i18n.locale === 'fr')
const store = useStore<State>()
const route = computed(() => store.state.route)
@@ -97,7 +98,8 @@ export default defineComponent({
changeColorMode,
updateScroll,
changeLanguage,
isWindow
isWindow,
isFrench
}
}
})

View File

@@ -2,7 +2,7 @@
<section class="w-full mb-10">
<h3 class="font-bold text-2xl md:text-4xl">
{{ $t('about.title.languages') }}
<TranslateIcon />
<LanguageIcon />
</h3>
<div>
<table class="text-base text-xl text-gray-700 dark:text-gray-400">
@@ -21,6 +21,6 @@
<script>
export default {
name: "LanguagesAbout"
name: "LanguagesAbout",
}
</script>

View File

@@ -51,22 +51,22 @@ export default defineComponent({
const toggleMenu = () => {
store.commit('TOGGLE_OPENED', !store.state.opened)
if (store.state.opened) {
document.getElementById('slider')!.style.maxHeight = window.screen.height + 'px'
setTimeout(() => document.getElementById('nav')!.classList.add('z-50'), 300)
} else {
document.getElementById('nav')!.classList.remove('z-50')
setTimeout(() => {
document.getElementById('slider')!.style.maxHeight = 'none'
}, 100)
}, 500)
}
}
const $router = useRouter()
$router.afterEach(() => {
store.commit('TOGGLE_OPENED', false)
document.getElementById('nav')!.classList.remove('z-50')
setTimeout(() => {
document.getElementById('slider')!.style.maxHeight = 'none'
}, 100)
}, 600)
})
return {

View File

@@ -2,7 +2,7 @@
<nuxt-link :to="`/blog/${slug}`">
<div class="rounded-lg dark:shadow-white shadow-xl h-116 w-full lg:w-100 text-left bg-gray-100 dark:bg-gray-800 transform hover:scale-103 duration-300 mb-8 lg:mb-0">
<div class="h-2/5 post rounded-t-lg"
:style="{ backgroundImage: `url(${getCover})` }">
:style="{ backgroundImage: `url(https://athena.arthurdanjou.fr/files/${cover})` }">
</div>
<div class="h-3/5 p-4 flex flex-col justify-between">
<div>
@@ -11,8 +11,8 @@
<Tag :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>
<h1 class="text-2xl font-bold">{{ $t(title) }}</h1>
<p class="text-base mt-3 text-gray-700 dark:text-gray-400 text-justify">{{ $t(description) }}</p>
</div>
<div class="flex justify-between">
<h5 class="text-base text-gray-700 dark:text-gray-400">{{ formatDate }}</h5>
@@ -69,8 +69,6 @@ export default defineComponent({
}
},
setup(props: PostProps) {
const getCover = computed(() => require(`~/assets/images/posts/${props.cover}`))
const { i18n } = useContext()
const formatDate = computed(() => {
const [first, second, third]: any = props.date.split('-')
@@ -78,7 +76,6 @@ export default defineComponent({
})
return {
getCover,
formatDate
}
}

View File

@@ -12,9 +12,9 @@
<div class="my-8 lg:flex w-full lg:space-x-6">
<div v-for="post in posts">
<Post
:title="post.title"
:cover="post.cover"
:description="post.description"
:title="post.title.code"
:cover="post.cover.file_name"
:description="post.description.code"
:date="post.date"
:slug="post.slug"
:tags="post.tags"
@@ -36,17 +36,21 @@ import {Post} from "~/types/types";
export default defineComponent({
name: "PostsHome",
setup() {
const { $content, i18n, $sentry } = useContext()
const { $axios, app, $sentry } = useContext()
const posts = useAsync(() => {
return $content(`articles/${i18n.locale}`)
.sortBy('date', 'asc')
.limit(3)
.fetch<Post>()
.catch((error) => {
$sentry.captureEvent(error)
const posts = useAsync(async () => {
const response = await $axios.get('/api/posts', {
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`
}
})
}, 'posts')
if (response.status === 200) {
return response.data.posts
} else {
app.error({statusCode: 500})
$sentry.captureEvent(response.data)
}
}, 'posts_home')
return {
posts

View File

@@ -4,7 +4,7 @@
<img class="rounded-full my-5" src="~/assets/images/memojies/Hey.png" alt="A picture of myself" />
</div>
<div class="text-lg leading-6 text-justify dark:text-gray-400 text-gray-700">
<p>{{ $t('about.banner.hello') }} <span class="text-indigo-600 font-bold">Arthur DANJOU</span> 👋.</p> <br/>
<div>{{ $t('about.banner.hello') }} <span class="text-indigo-600 font-bold">Arthur DANJOU</span> 👋.</div> <br/>
<p>{{ $t('about.banner.1')}}</p> <br/>
<p>{{ $t('about.banner.2') }}</p> <br/>
<p>{{ $t('about.banner.3') }}</p> <br />

View File

@@ -1,14 +1,14 @@
<template>
<a :href="url" target="_blank">
<div class="rounded-lg dark:shadow-white shadow-xl h-92 w-full lg:w-84 text-left bg-gray-100 dark:bg-gray-800 transform hover:scale-103 duration-300 mb-8 lg:mb-0">
<div class="h-1/2 w-full h-2/5 project rounded-t-lg"
:style="{ backgroundImage: `url(${getCover})` }">
<div class="rounded-lg dark:shadow-white shadow-xl lg:h-92 w-full lg:w-84 text-left bg-gray-100 dark:bg-gray-800 transform hover:scale-103 duration-300 mb-8 lg:mb-0">
<div class="h-64 lg:h-1/2 w-full project rounded-t-lg"
:style="{ backgroundImage: `url(https://athena.arthurdanjou.fr/files/${cover})` }">
</div>
<div class="h-1/2 p-4 flex flex-col justify-between">
<div class="lg:h-1/2 py-8 px-4 lg:p-4 flex flex-col justify-between">
<div>
<div class="flex space-x-2 mb-2">
<div v-for="tag in tags">
<Tag :content="tag" :pill="false"/>
<Tag :content="tag.label.code" :pill="false"/>
</div>
</div>
<h1 class="text-2xl font-bold">{{ title }}</h1>
@@ -20,15 +20,7 @@
</template>
<script lang="ts">
import {computed, defineComponent} from "@nuxtjs/composition-api";
interface ProjectProp {
title: string,
cover: string,
tags: Array<String>,
description: string,
url: string,
}
import {defineComponent} from "@nuxtjs/composition-api";
export default defineComponent({
name: "Project",
@@ -53,13 +45,6 @@ export default defineComponent({
type: String,
default: 'https://arthurdanjou.fr'
}
},
setup(props: ProjectProp) {
const getCover = computed(() => require(`@/assets/images/projects/${props.cover}`))
return {
getCover
}
}
})
</script>

View File

@@ -9,12 +9,12 @@
{{ $t('projects.description') }}
</p>
</div>
<div class="my-8 lg:flex w-full lg:space-x-8 flex flex-wrap justify-center">
<div class="my-8 w-full lg:space-x-8 lg:flex justify-center">
<div v-for="project in projects" class="mb-4">
<Project
:title="project.title"
:cover="project.cover"
:description="project.description"
:title="project.name"
:cover="project.cover.file_name"
:description="project.description.code"
:tags="project.tags"
:url="project.url"
/>
@@ -34,16 +34,21 @@ import {Project} from "~/types/types";
export default defineComponent({
name: "ProjectsHome",
setup() {
const { $content, $sentry } = useContext()
const { $axios, app, $sentry } = useContext()
const projects = useAsync(() => {
return $content(`projects`)
.limit(3)
.fetch<Project>()
.catch((error) => {
$sentry.captureEvent(error)
const projects = useAsync(async () => {
const response = await $axios.get('/api/projects', {
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`
}
})
}, 'projects')
if (response.status === 200) {
return response.data.projects.slice(0, 3)
} else {
$sentry.captureEvent(response.data)
app.error({statusCode: 500})
}
}, 'projects_home')
return {
projects

View File

@@ -17,7 +17,7 @@
<ul class="flex items-center">
<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-400">
<TranslateIcon/>
<TranslateIcon :french="isFrench" />
</li>
<li @click="changeColorMode()"
class="mx-1 h-9 w-9 cursor-pointer flex items-center p-1.5 rounded-xl hover:bg-gray-300 dark:hover:bg-dark-400 duration-200">
@@ -90,7 +90,7 @@
<a target="_blank" href="https://www.twitch.tv/arthurdanjou" rel="noopener noreferrer">
<TwitchIcon />
</a>
<a target="_blank" href="https://discord.gg/RQhjE5UkxD" rel="noopener noreferrer">
<a target="_blank" href="https://discord.gg/ENG6cFQhPS" rel="noopener noreferrer">
<DiscordIcon />
</a>
<a target="_blank" href="mailto:contact@arthurdanjou.fr" rel="noopener noreferrer">
@@ -130,13 +130,15 @@ export default defineComponent({
}
})
const isFrench = computed(() => i18n.locale === 'fr')
const store = useStore<State>()
const closeMenu = () => {
store.commit('TOGGLE_OPENED', false)
document.getElementById('nav')!.classList.remove('z-50')
setTimeout(() => {
document.getElementById('slider')!.style.maxHeight = 'none'
}, 100)
}, 500)
}
const route = computed(() => store.state.route)
@@ -150,7 +152,8 @@ export default defineComponent({
changeLanguage,
closeMenu,
opened: computed(() => store.state.opened),
isWindow
isWindow,
isFrench
}
}
})

View File

@@ -0,0 +1,14 @@
<template>
<svg class="inline" width="1em" height="1em" viewBox="0 0 24 24" focusable="false">
<path
d="M12.87 15.07l-2.54-2.51l.03-.03A17.52 17.52 0 0 0 14.07 6H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35C8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5l3.11 3.11l.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"
fill="currentColor"
/>
</svg>
</template>
<script>
export default {
name: "LanguageIcon"
}
</script>

View File

@@ -1,14 +1,40 @@
<template>
<svg class="inline" width="1.5em" height="1.5em" viewBox="0 0 24 24" focusable="false">
<svg v-if="french" class="inline" width="1.5em" height="1.5em" viewBox="0 0 36 36" focusable="false">
<path
d="M12.87 15.07l-2.54-2.51l.03-.03A17.52 17.52 0 0 0 14.07 6H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35C8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5l3.11 3.11l.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"
fill="currentColor"
/>
fill="#00247D"
d="M0 9.059V13h5.628zM4.664 31H13v-5.837zM23 25.164V31h8.335zM0 23v3.941L5.63 23zM31.337 5H23v5.837zM36 26.942V23h-5.631zM36 13V9.059L30.371 13zM13 5H4.664L13 10.837z" />
<path
fill="#CF1B2B"
d="M25.14 23l9.712 6.801a3.977 3.977 0 0 0 .99-1.749L28.627 23H25.14zM13 23h-2.141l-9.711 6.8c.521.53 1.189.909 1.938 1.085L13 23.943V23zm10-10h2.141l9.711-6.8a3.988 3.988 0 0 0-1.937-1.085L23 12.057V13zm-12.141 0L1.148 6.2a3.994 3.994 0 0 0-.991 1.749L7.372 13h3.487z" />
<path
fill="#EEE"
d="M36 21H21v10h2v-5.836L31.335 31H32a3.99 3.99 0 0 0 2.852-1.199L25.14 23h3.487l7.215 5.052c.093-.337.158-.686.158-1.052v-.058L30.369 23H36v-2zM0 21v2h5.63L0 26.941V27c0 1.091.439 2.078 1.148 2.8l9.711-6.8H13v.943l-9.914 6.941c.294.07.598.116.914.116h.664L13 25.163V31h2V21H0zM36 9a3.983 3.983 0 0 0-1.148-2.8L25.141 13H23v-.943l9.915-6.942A4.001 4.001 0 0 0 32 5h-.663L23 10.837V5h-2v10h15v-2h-5.629L36 9.059V9zM13 5v5.837L4.664 5H4a3.985 3.985 0 0 0-2.852 1.2l9.711 6.8H7.372L.157 7.949A3.968 3.968 0 0 0 0 9v.059L5.628 13H0v2h15V5h-2z" />
<path
fill="#CF1B2B"
d="M21 15V5h-6v10H0v6h15v10h6V21h15v-6z" />
</svg>
<svg v-else class="inline" width="1.5em" height="1.5em" viewBox="0 0 36 36" focusable="false">
<path
fill="#ED2939"
d="M36 27a4 4 0 0 1-4 4h-8V5h8a4 4 0 0 1 4 4v18z" />
<path
fill="#002495"
d="M4 5a4 4 0 0 0-4 4v18a4 4 0 0 0 4 4h8V5H4z" />
<path
fill="#EEE"
d="M12 5h12v26H12z" />
</svg>
</template>
<script>
export default {
name: "TranslateIcon"
name: "TranslateIcon",
props: {
french: {
type: Boolean,
default: true
}
}
}
</script>

View File

@@ -1,11 +1,5 @@
---
slug: how-i-start
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.png
date: 07-01-2021
---
## Presentation

View File

@@ -1,11 +1,5 @@
---
slug: new-version-new-website
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.png
date: 13-12-2020
---
## Presentation

View File

@@ -1,11 +1,5 @@
---
slug: how-i-start
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.png
date: 07-01-2021
---
## Présentation

View File

@@ -1,11 +1,5 @@
---
slug: new-version-new-website
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.png
date: 13-12-2020
---
## Présentation

View File

@@ -1,34 +0,0 @@
[
{
"slug": "erisium",
"title": "Erisium",
"description": "works.erisium",
"url": "https://erisium.com",
"cover": "erisium.png",
"tags": ["tags.mc"]
},
{
"slug": "ares",
"title": "Ares",
"description": "works.ares",
"url": "https://arthurdanjou.fr",
"cover": "ares.png",
"tags": ["tags.web"]
},
{
"slug": "athena",
"title": "Athena",
"description": "works.athena",
"url": "https://athena.arthurdanjou.fr",
"cover": "athena.png",
"tags": ["tags.api"]
},
{
"slug": "linkyjs",
"title": "LinkyJs",
"description": "works.linkyjs",
"url": "https://github.com/linkyjs/",
"cover": "linkyjs.png",
"tags": ["tags.software", "tags.opensource"]
}
]

View File

@@ -1,11 +0,0 @@
[
{
"slug": "tags.dev"
},
{
"slug": "tags.tech"
},
{
"slug": "tags.life"
}
]

View File

@@ -6,7 +6,6 @@
id="slider"
class="xl:static shadow-2xl transition-all duration-500 overflow-hidden xl:overflow-visible"
:class="{'transform scale-90 md:scale-70 lg:scale-60 xl:scale-100 rounded-lg xl:rounded-none translate-x-10/12 sm:translate-x-4/12 lg:translate-x-3/12 xl:translate-x-0': opened}"
:style="`max-height: ${height}px`"
:tabindex="opened ? -1 : 0"
>
<div
@@ -41,17 +40,14 @@ export default {
const closeMenu = () => {
store.commit('TOGGLE_OPENED', false)
document.getElementById('nav')!.classList.remove('z-50')
setTimeout(() => {
document.getElementById('slider')!.style.maxHeight = 'none'
}, 500)
}
const height = ref(0)
onMounted(() => {
height.value = window.screen.height
})
return {
opened: computed(() => store.state.opened),
closeMenu,
height,
}
}
}

View File

@@ -0,0 +1,9 @@
<template>
<Nuxt />
</template>
<script>
export default {
name: "maintenance"
}
</script>

View File

@@ -47,7 +47,7 @@ const translations = {
},
footer: {
description: 'Développeur Web et Logiciel, mais également étudiant en Mathématiques et en Physique. Je développe des sites internet',
description: "Web and Software Developer, but also student in Mathematics and Physics 🎓. I live in Paris 🇫🇷. I love to create more or less useful applications and software 🛍. I use modern technologies to get the best possible result ✨ I also adore contributing to all types of Open-Source projects 🧪",
links: 'Quick links',
credits: 'Developed with',
credits_separator: 'and',
@@ -115,7 +115,7 @@ const translations = {
1: 'I am a young creative developer who loves to tinker and touch everything! I am very interested in new technologies, development and IT.',
2: 'I love sharing my knowledge and helping others through lives on Twitchs, technical articles on my blog, open-source projects or by reviewing community code. As long as I share my passions, I will continue to do this.',
3: 'I am able to quickly learn new technologies to meet the needs of different projects. I often identify the need for new systems or tools to improve workflow efficiency. I am always motivated by a challenge and like to be well organized to produce consistent results.',
4: 'En parallèle du développement, je suis étudiant en Mathématiques et en Physique dans la faculté des Sciences Paris-Saclay. De plus, je suis un grand fan de moto.'
4: 'In parallel with the development, I am a student in Mathematics and Physics in the Paris-Saclay Faculty of Sciences. In addition, I am a big fan of motorcycles.'
},
title: {
skills: 'Skills',
@@ -252,7 +252,14 @@ const translations = {
linkyjs: 'LinkyJS is my custom and Open-Source url shortener'
},
loading: 'Loading...'
loading: 'Loading...',
maintenance: {
back_soon: "We'll be back soon...",
title: 'Website under maintenance !',
progress: "To follow the progress: ",
separator: 'or'
}
}
export default async function () {

View File

@@ -47,7 +47,7 @@ const translations = {
},
footer: {
description: 'Développeur Web et Logiciel, mais également étudiant en Mathématiques et en Physique. Je développe des sites internet',
description: "Développeur Web et Logiciel, mais aussi étudiant en Mathématiques et Physique 🎓. J'habite à Paris 🇫🇷. J'adore créer des applications et des logiciels plus ou moins utiles 🛍. J'utilise les technologies modernes pour obtenir le meilleur résultat possible ✨ J'adore également contribuer à tous types de projets Open-Source 🧪",
links: 'Liens rapides',
credits: 'Développé avec',
credits_separator: 'et',
@@ -252,7 +252,14 @@ const translations = {
linkyjs: "LinkyJS est mon raccourcisseur d'url personnalisé et Open-Source."
},
loading: 'Chargement...'
loading: 'Chargement...',
maintenance: {
back_soon: "Nous serons de retour bientôt...",
title: 'Site en maintenance !',
progress: "Pour suivre l'avancée : ",
separator: 'ou'
}
}
export default async function () {

View File

@@ -0,0 +1,19 @@
import {Context} from "@nuxt/types";
export default async function ({redirect, route, $axios}: Context) {
let isMaintenance = true
const response = await $axios.get('/api/maintenance', {
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`
}
})
if (response.status === 200) {
isMaintenance = response.data.maintenance.active === 1
}
if(isMaintenance){
return redirect('/maintenance')
}
if(!isMaintenance && route.path === '/maintenance'){
return redirect('/')
}
}

View File

@@ -1,6 +1,7 @@
<template>
<main v-if="post" class="blog flex flex-col items-center px-4 xl:px-72 mb-16 md:mb-32">
<main v-if="post && postData" class="blog flex flex-col items-center px-4 xl:px-72 mb-16 md:mb-32">
<div class="mt-8 md:mt-32 flex flex-col justify-around py-8 w-full">
{{ slug }}
<div>
<div class="mb-4 flex">
<nuxt-link to="/blog" class="back-arrow flex">
@@ -14,10 +15,10 @@
</div>
</div>
<h1 class="text-3xl md:text-5xl font-bold">
{{ post.title }}
{{ $t(postData.title.code) }}
</h1>
<h3 class="text-xl text-gray-800 dark:text-gray-300 my-4 md:mt-8">
{{ post.description }}
{{ $t(postData.description.code) }}
</h3>
<div class="flex flex-row justify-between w-full md:w-2/3 mb-12">
<div>
@@ -26,16 +27,16 @@
</div>
<div>
<p class="uppercase text-sm font-bold text-gray-800 dark:text-gray-400">{{ $t('blog.read.time') }}</p>
<p>{{ post.reading_time }} min</p>
<p>{{ postData.reading_time }} min</p>
</div>
<div>
<p :class="post.tags.length === 0 ? 'opacity-0': 'opacity-100'" class="uppercase text-sm font-bold text-gray-800 dark:text-gray-400">Tags</p>
<p :class="postData.tags.length === 0 ? 'opacity-0': 'opacity-100'" class="uppercase text-sm font-bold text-gray-800 dark:text-gray-400">Tags</p>
<p>{{ formatTags }}</p>
</div>
</div>
<div class="w-full">
<div class="flex justify-center w-full">
<img class="w-full" :src="require(`@/assets/images/posts/${post.cover}`)" alt="Cover Img" />
<img class="w-full" :src="`https://athena.arthurdanjou.fr/files/${postData.cover.file_name}`" alt="Cover Img" />
</div>
</div>
<nuxt-content
@@ -55,7 +56,7 @@
:class="liked ? 'border-red-500 dark:border-red-500 hover:border-gray-400 dark:hover:border-dark-200' : 'border-gray-400 dark:border-dark-200 hover:border-red-500 dark:hover:border-red-500'"
>
<div class="mr-2 lining-nums leading-3">
{{ likes }}
{{ getLikes }}
</div>
<div class="inline leading-6" :class="{'animate-pulse heartbeat': liked}">
<HeartIcon :liked="liked"/>
@@ -63,7 +64,7 @@
</div>
<a
target="_blank"
:href="'https://twitter.com/intent/tweet?url=https%3A%2F%2Farthurdanjou.fr%2Fblog%2F' + this.post.slug + '&text=' + $t('blog.tweet') + ' ' + post.title"
:href="'https://twitter.com/intent/tweet?url=https%3A%2F%2Farthurdanjou.fr%2Fblog%2F' + postData.slug + '&text=' + $t('blog.tweet') + ' ' + $i18n.t('title')"
class="mr-2 icon-hover cursor-pointer duration-300 text-2xl p-1 border-solid border border-gray-300 dark:border-dark-200 hover:border-cyan-500 dark:hover:border-cyan-400 flex justify-center items-center"
>
<TwitterBlogIcon />
@@ -119,7 +120,7 @@ export default defineComponent({
const slug = computed(() => route.value.params.slug)
const post = useStatic((slug) => {
return $content(`articles/${i18n.locale}`, slug)
return $content(i18n.locale, slug)
.fetch<Post>()
.catch((error) => {
app.error({statusCode: 404, message: "Post not found"})
@@ -127,31 +128,34 @@ export default defineComponent({
}) as Promise<Post>
}, slug, 'post')
title.value = post.value?.title ? `Blog - Arthur Danjou - ${post.value!.title}` : 'Loading title...'
watch(post, () => {
title.value = post.value?.title ? `Blog - Arthur Danjou - ${post.value!.title}` : 'Loading title...'
})
const liked = ref($storage.getCookie(`${slug.value}`) !== undefined)
const likes = ref(0)
const getLikes = computed(() => likes.value)
const likes = useAsync(async () => {
const response = await $axios.get(`/api/posts/${slug.value}`, {
const postData = useAsync(async () => {
const response = await $axios.get(`/api/posts/${slug.value}/data`, {
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`
}
})
if (response.status === 200) {
return response.data.likes
likes.value = response.data.post.likes
title.value = `Blog - Arthur Danjou - ${i18n.t(response.data.post.title.code)}`
return response.data.post
} else {
$sentry.captureEvent(response.data)
app.error({statusCode: 500})
}
}, 'likes')
}, 'postData')
watch(postData, () => {
title.value = `Blog - Arthur Danjou - ${i18n.t(postData.value.title.code)}`
likes.value = postData.value.likes
})
const handleLike = async () => {
if (liked.value) {
const response = await $axios.post(`/api/posts/${post.value?.slug}/unlike`, {}, {
const response = await $axios.post(`/api/posts/${postData.value.slug}/unlike`, {}, {
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`
}
@@ -165,7 +169,7 @@ export default defineComponent({
app.error({statusCode: 500})
}
} else {
const response = await $axios.post(`/api/posts/${post.value?.slug}/like`, {}, {
const response = await $axios.post(`/api/posts/${postData.value.slug}/like`, {}, {
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`
}
@@ -185,7 +189,7 @@ export default defineComponent({
const isCopied = ref(false)
const copyToClipboard = () => {
navigator.clipboard.writeText('https://arthurdanjou.fr/blog/' + post.value?.slug)
navigator.clipboard.writeText('https://arthurdanjou.fr/blog/' + postData.value.slug)
isCopied.value = true
setTimeout(() => {
isCopied.value = false
@@ -200,13 +204,13 @@ export default defineComponent({
}
const formatDate = computed(() => {
const [first, second, third]: any = post.value?.date.split('-')
const [first, second, third]: any = postData.value.date.split('-')
return `${first} ${i18n.t(`month.${second}`)} ${third}`
})
const formatTags = computed(() => {
let tags = ""
post.value?.tags.map(tag => {
postData.value.tags.map(tag => {
tags += i18n.t(String(tag)) + ", "
})
return tags.substring(0, tags.length - 2)
@@ -214,14 +218,16 @@ export default defineComponent({
return {
post,
likes,
getLikes,
liked,
handleLike,
isCopied,
copyToClipboard,
scrollToTop,
formatDate,
formatTags
formatTags,
postData,
slug
}
}
})

View File

@@ -9,9 +9,9 @@
<div class="flex py-8 w-full flex-wrap">
<div class="md:mx-8 my-4 w-full lg:w-auto" v-for="post in posts">
<Post
:title="post.title"
:cover="post.cover"
:description="post.description"
:title="post.title.code"
:cover="post.cover.file_name"
:description="post.description.code"
:date="post.date"
:slug="post.slug"
:tags="post.tags"
@@ -41,20 +41,25 @@ export default defineComponent({
}
},
setup() {
const { $content, i18n, $sentry } = useContext()
const { $sentry, $axios, app } = useContext()
const posts = useAsync(() => {
return $content(`articles/${i18n.locale}`)
.sortBy('date', 'asc')
.limit(10)
.fetch<Post>()
.catch((error) => {
$sentry.captureEvent(error)
const posts = useAsync(async () => {
const response = await $axios.get('/api/posts', {
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`
}
})
if (response.status === 200) {
console.log(response.data.posts)
return response.data.posts
} else {
app.error({statusCode: 500})
$sentry.captureEvent(response.data)
}
}, 'posts')
return {
posts,
posts
}
}
})

107
src/pages/maintenance.vue Normal file
View File

@@ -0,0 +1,107 @@
<template>
<div v-if="maintenance" class="w-screen h-screen flex items-center">
<div class="absolute right-4 top-4">
<ul class="flex items-center">
<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-400">
<TranslateIcon :french="isFrench"/>
</li>
<li @click="changeColorMode()"
class="mx-1 h-9 w-9 cursor-pointer flex items-center p-1.5 rounded-xl hover:bg-gray-300 dark:hover:bg-dark-400 duration-200">
<div v-if="this.$colorMode.preference === 'light'">
<MoonIcon/>
</div>
<div v-else>
<SunIcon/>
</div>
</li>
</ul>
</div>
<div class="w-full flex flex-col items-center">
<div class="self-center">
<div class="flex justify-center mb-8">
<img class="w-full lg:w-3/4 xl:w-1/3" src="@/assets/images/maintenance.png" alt="Maintenance Image" />
</div>
<div class="text-center">
<h3 class="text-xl lg:text-2xl">
{{ $t('maintenance.back_soon') }}
</h3>
<h1 class="font-black text-3xl lg:text-5xl my-4">
{{ $t('maintenance.title') }}
</h1>
<p class="text-gray-600 dark:text-gray-400 text-md lg:text-xl">
{{ $t(maintenance.reason.code) }}
</p>
</div>
</div>
<div class="lg:w-2/3 p-4 lg:p-8 mt-auto w-full ">
<div class="py-4 text-center border-t-2 border-gray-200 dark:border-gray-800 social-links">
{{ $t('maintenance.progress') }} <br class="lg:hidden"/>
<a target="_blank" href="https://twitter.com/ArthurDanj" rel="noopener noreferrer">
<TwitterIcon />
</a>
<div class="mx-2 inline">{{ $t('maintenance.separator') }}</div>
<a target="_blank" href="https://discord.gg/ENG6cFQhPS" rel="noopener noreferrer">
<DiscordIcon />
</a>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import {computed, defineComponent, useAsync, useContext} from "@nuxtjs/composition-api";
export default defineComponent({
name: "maintenance",
layout: 'maintenance',
setup() {
const {$axios, $sentry, app} = useContext()
const maintenance = useAsync(async () => {
const response = await $axios.get('/api/maintenance', {
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`
}
})
if (response.status === 200) {
return response.data.maintenance
} else {
$sentry.captureEvent(response.data)
app.error({statusCode: 500})
}
}, 'maintenance')
const {i18n} = useContext()
const changeLanguage = () => useAsync(() => {
i18n.setLocale(i18n.locale === 'fr' ? 'en' : 'fr')
})
const isFrench = computed(() => i18n.locale === 'fr')
const {$colorMode} = useContext()
const changeColorMode = () => {
$colorMode.preference = $colorMode.value === 'light' ? 'dark' : 'light'
}
return {
maintenance,
changeLanguage,
isFrench,
changeColorMode
}
}
})
</script>
<style lang="scss">
.social-links a {
svg {
@apply h-6 w-6 duration-300
}
&:hover svg {
@apply transform hover:scale-120
}
}
</style>

View File

@@ -5,12 +5,12 @@
<div v-else class="flex flex-col justify-around items-center py-10 w-full">
<h1 class="text-gray-700 dark:text-gray-400 text-xl mt-4">{{ $t('projects.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 class="flex py-4 w-full flex-wrap justify-center">
<div class="md:mx-4 my-4 w-full lg:w-auto" v-for="project in projects">
<div class="lg:flex py-4 w-full flex-wrap justify-center">
<div class="m-4" v-for="project in projects">
<Project
:title="project.title"
:cover="project.cover"
:description="project.description"
:title="project.name"
:cover="project.cover.file_name"
:description="project.description.code"
:tags="project.tags"
:url="project.url"
/>
@@ -33,14 +33,20 @@ export default defineComponent({
}
},
setup() {
const { $content, $sentry } = useContext()
const { $axios, app, $sentry } = useContext()
const projects = useAsync(() => {
return $content('projects')
.fetch<Project>()
.catch((error) => {
$sentry.captureEvent(error)
const projects = useAsync(async () => {
const response = await $axios.get('/api/projects', {
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`
}
})
if (response.status === 200) {
return response.data.projects
} else {
$sentry.captureEvent(response.data)
app.error({statusCode: 500})
}
}, 'projects')
return {

View File

@@ -1414,17 +1414,17 @@
defu "^5.0.0"
lodash.template "^4.5.0"
"@nuxtjs/composition-api@^0.26.0":
version "0.26.0"
resolved "https://registry.yarnpkg.com/@nuxtjs/composition-api/-/composition-api-0.26.0.tgz#0fbda4fc942ca1e346b7c6d55a1fb331ff931a2a"
integrity sha512-+4L9YDEN5h/vBY6xbBKPMIhgxbPv7psE4IVgKlF+QIekou6oN8m0T+QR2JLE0dHKwzicUbZLCr1v2Qw5T7L48A==
"@nuxtjs/composition-api@^0.27.0":
version "0.27.0"
resolved "https://registry.yarnpkg.com/@nuxtjs/composition-api/-/composition-api-0.27.0.tgz#cbe4df6a7306e4a34770fbad5b1ad79717f8fdb7"
integrity sha512-YtQ1KX+ls13zbukII8/vhKskoI1FrngDxegGVW31576qlaiEQUQGpOATF0cGrZ1W7Wgmz3rsAz1CNdSd5FFXOA==
dependencies:
"@vue/composition-api" "^1.0.4"
"@vue/composition-api" "^1.1.1"
defu "^5.0.0"
estree-walker "^2.0.2"
fs-extra "^9.1.0"
magic-string "^0.25.7"
ufo "^0.7.7"
ufo "^0.7.9"
upath "^2.0.1"
"@nuxtjs/dotenv@^1.4.1":
@@ -1470,17 +1470,17 @@
resolved "https://registry.yarnpkg.com/@nuxtjs/robots/-/robots-2.5.0.tgz#a42b25e3bc58181cb2a8fbd30d6b0fee6c36bc60"
integrity sha512-z1F3HXb05NiZga8Cuq6k5bbowfJOScPtbSOakip0nege+1aI9pGoajzap8eR5s1qwLXAk9Ts+NcgetoUn5lwrQ==
"@nuxtjs/sentry@^5.1.0":
version "5.1.1"
resolved "https://registry.yarnpkg.com/@nuxtjs/sentry/-/sentry-5.1.1.tgz#329606bf93f804d18769cf26befd6786b86e0480"
integrity sha512-tJq4I0r3M46WMO8oPIRVZ05VjXJrzuWCPYNRmhg2q2jcKgHaetK60RnJwGcnsDz6x92MLFVhdzA5kiJEIe9/7Q==
"@nuxtjs/sentry@^5.1.2":
version "5.1.2"
resolved "https://registry.yarnpkg.com/@nuxtjs/sentry/-/sentry-5.1.2.tgz#ba856e4b35676f5be9adfbe73cfa5b785fb0051c"
integrity sha512-WdEa22ynTkFr2FQo3FZEEr5derBu2ckBvAYE5897kJvYp5dI65PK0dKRilPbHikrfb0hUWaPp2dH6Ke1VvGElw==
dependencies:
"@sentry/browser" "^6.11.0"
"@sentry/integrations" "^6.11.0"
"@sentry/node" "^6.11.0"
"@sentry/webpack-plugin" "^1.17.1"
consola "^2.15.3"
lodash.merge "^4.6.2"
lodash.mergewith "^4.6.2"
"@nuxtjs/sitemap@^2.4.0":
version "2.4.0"
@@ -2106,10 +2106,10 @@
optionalDependencies:
prettier "^1.18.2"
"@vue/composition-api@^1.0.4":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@vue/composition-api/-/composition-api-1.1.0.tgz#484e7e3bbc516ad6a9b0a9967d316325c239539e"
integrity sha512-9TMJliVFByhfEJjqM+Ymu9ImVrUnrT/Y2S7Fz8EsQ1MbggbE0o8Ohvk9XqK2UIOp8w68f7goVX+6h6O78iRsJQ==
"@vue/composition-api@^1.1.1":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@vue/composition-api/-/composition-api-1.1.3.tgz#8fa528c5f68fec47363340fdae7c7fe047ba5e10"
integrity sha512-gFcLkHD7SkaoE+i4OhMtv6c/gQeSYxEDDGk4yzF4tZ8h8+7oFNBX8lPUWf9McHGBTcztZNzsIZuwkDVmc0WZlQ==
dependencies:
tslib "^2.3.0"
@@ -3392,10 +3392,10 @@ core-js@^2.6.5:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
core-js@^3.16.1:
version "3.16.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.16.1.tgz#f4485ce5c9f3c6a7cb18fa80488e08d362097249"
integrity sha512-AAkP8i35EbefU+JddyWi12AWE9f2N/qr/pwnDtWz4nyUIBGMJPX99ANFFRSw6FefM374lDujdtLDyhN2A/btHw==
core-js@^3.16.2:
version "3.16.2"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.16.2.tgz#3f485822889c7fc48ef463e35be5cc2a4a01a1f4"
integrity sha512-P0KPukO6OjMpjBtHSceAZEWlDD1M2Cpzpg6dBbrjFqFhBHe/BwhxaP820xKOjRn/lZRQirrCusIpLS/n2sgXLQ==
core-util-is@~1.0.0:
version "1.0.2"
@@ -5773,6 +5773,11 @@ lodash.merge@^4.6.2:
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
lodash.mergewith@^4.6.2:
version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
lodash.template@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab"
@@ -8275,10 +8280,10 @@ sass-loader@10.1.1:
schema-utils "^3.0.0"
semver "^7.3.2"
sass@^1.37.5:
version "1.37.5"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.37.5.tgz#f6838351f7cc814c4fcfe1d9a20e0cabbd1e7b3c"
integrity sha512-Cx3ewxz9QB/ErnVIiWg2cH0kiYZ0FPvheDTVC6BsiEGBTZKKZJ1Gq5Kq6jy3PKtL6+EJ8NIoaBW/RSd2R6cZOA==
sass@^1.38.0:
version "1.38.0"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.38.0.tgz#2f3e60a1efdcdc910586fa79dc89d3399a145b4f"
integrity sha512-WBccZeMigAGKoI+NgD7Adh0ab1HUq+6BmyBUEaGxtErbUtWUevEbdgo5EZiJQofLUGcKtlNaO2IdN73AHEua5g==
dependencies:
chokidar ">=3.0.0 <4.0.0"
@@ -9178,6 +9183,11 @@ ufo@^0.7.4, ufo@^0.7.5, ufo@^0.7.7:
resolved "https://registry.yarnpkg.com/ufo/-/ufo-0.7.7.tgz#0062f9e5e790819b0fb23ca24d7c63a4011c036a"
integrity sha512-N25aY3HBkJBnahm+2l4JRBBrX5I+JPakF/tDHYDTjd3wUR7iFLdyiPhj8mBwBz21v728BKwM9L9tgBfCntgdlw==
ufo@^0.7.9:
version "0.7.9"
resolved "https://registry.yarnpkg.com/ufo/-/ufo-0.7.9.tgz#0268e3734b413c9ed6f3510201f42372821b875c"
integrity sha512-6t9LrLk3FhqTS+GW3IqlITtfRB5JAVr5MMNjpBECfK827W+Vh5Ilw/LhTcHWrt6b3hkeBvcbjx4Ti7QVFzmcww==
uglify-js@^3.5.1:
version "3.14.1"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.14.1.tgz#e2cb9fe34db9cb4cf7e35d1d26dfea28e09a7d06"