mirror of
https://github.com/ArthurDanjou/website-old.git
synced 2026-01-24 17:00:33 +01:00
Working
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -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
107
src/pages/maintenance.vue
Normal 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>
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user