💻 | Update all components with Composition API and TypeScript & Add images

This commit is contained in:
2021-03-22 21:48:26 +01:00
parent f2d420a87a
commit 03db9ff299
49 changed files with 770 additions and 69 deletions

2
index.d.ts vendored
View File

@@ -1,5 +1,6 @@
import { NuxtAxiosInstance } from '@nuxtjs/axios'
import VueI18n, {IVueI18n} from "vue-i18n";
import {ColorModeInstance} from "@nuxtjs/color-mode/types/color-mode";
declare module 'vue/types/vue' {
@@ -16,6 +17,7 @@ declare module '@nuxt/types' {
interface Context {
$axios: NuxtAxiosInstance,
$i18n: VueI18n & IVueI18n
$colorMode: ColorModeInstance
}
}

BIN
src/assets/images/Logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

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

After

Width:  |  Height:  |  Size: 228 B

View File

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

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="256px" height="191px" viewBox="0 0 256 191" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 59.1 (86144) - https://sketch.com -->
<title>Group</title>
<desc>Created with Sketch.</desc>
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(0.000173, 0.000000)">
<path d="M77.8911791,183.614864 C77.7012551,183.279 77.5321086,182.931804 77.384692,182.575232 C76.3622173,180.209762 76.0473968,177.598605 76.478347,175.057899 L15.9931374,175.057899 L105.88125,16.874014 L135.390782,68.7489446 L143.947746,53.6076496 L118.223538,8.29039232 C117.503793,6.98418906 113.158668,0 105.667993,0 C102.282527,0 97.4309144,1.46614656 93.485647,8.39702119 L2.42461749,168.500225 C1.65155838,169.8864 -2.10710822,177.163819 1.62490116,183.614864 C3.33096269,186.547156 6.9563432,190.039251 14.9535063,190.039251 L91.2197845,190.039251 C83.2759358,190.039251 79.5972406,186.600471 77.8911791,183.614864 Z" fill="#01C58E" />
<path d="M253.242307,168.500225 L178.415518,36.6803211 C177.64246,35.2941462 173.323992,28.2832999 165.806658,28.2832999 C162.421193,28.2832999 157.56958,29.7227893 153.624314,36.6536639 L143.947746,53.6076496 L152.558025,68.7489446 L165.88663,45.157314 L239.913702,175.057899 L211.763688,175.057899 C212.123898,177.20534 211.921853,179.409465 211.17723,181.45563 C211.020409,181.907379 210.824167,182.344463 210.590771,182.761832 L210.350856,183.241662 C206.565533,189.692707 198.381769,190.039251 196.782337,190.039251 L240.820047,190.039251 C242.446137,190.039251 250.603243,189.692707 254.388568,183.241662 C256.067972,180.309369 257.267546,175.377785 253.242307,168.500225 Z" fill="#108775" />
<path d="M210.350856,183.241662 L210.590771,182.761832 C210.824167,182.344463 211.020409,181.907379 211.17723,181.45563 C211.921853,179.409465 212.123898,177.20534 211.763688,175.057899 C211.348809,172.741872 210.517913,170.520128 209.311226,168.500225 L152.611339,68.7489446 L143.947746,53.6076496 L135.337467,68.7489446 L78.6642383,168.500225 C77.5638612,170.544123 76.8243845,172.762554 76.478347,175.057899 C76.0222311,177.590906 76.3092441,180.201797 77.3047209,182.575232 C77.4521368,182.931805 77.6212834,183.279 77.8112079,183.614864 C79.5172694,186.547156 83.1426494,190.039251 91.1398127,190.039251 L196.702365,190.039251 C198.381769,190.039251 206.565533,189.692707 210.350856,183.241662 L210.350856,183.241662 Z M143.947746,83.89024 L195.769362,175.057899 L92.1527868,175.057899 L143.947746,83.89024 Z" fill="#2F495E" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,12 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="-92.4 101 489.5 512" enable-background="new -92.4 101 489.5 512" xml:space="preserve">
<g>
<path fill="#65459B" d="M263.6,546.1H163.4L96.7,613H30v-66.9H-92.4v-356l33.3-89.1h456.2v311.6L263.6,546.1z M352.7,390.5V145.5
H-14.6v322.7H85.6V535l66.7-66.7h122.4L352.7,390.5z"/>
<g id="Solo_Glitch_136_">
<g>
<path fill="#65459B" d="M230.2,234.6v133.6h44.5V234.6H230.2z M107.8,368.1h44.5V234.6h-44.5V368.1z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 573 B

View File

@@ -0,0 +1 @@
<svg id="twitter" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 126.24 102.59"><defs><style>.cls-1{fill:#1da1f2;}</style></defs><title>twitter-original</title><path id="original" class="cls-1" d="M40.58,115.3c47.64,0,73.69-39.47,73.69-73.69,0-1.12,0-2.24-.07-3.35a52.7,52.7,0,0,0,12.92-13.41,51.7,51.7,0,0,1-14.87,4.08A26,26,0,0,0,123.63,14.6a51.9,51.9,0,0,1-16.45,6.29A25.92,25.92,0,0,0,63.05,44.51,73.53,73.53,0,0,1,9.67,17.45a25.92,25.92,0,0,0,8,34.58A25.71,25.71,0,0,1,6,48.78c0,.11,0,.22,0,.33A25.91,25.91,0,0,0,26.73,74.5a25.86,25.86,0,0,1-11.7.44,25.93,25.93,0,0,0,24.2,18A52,52,0,0,1,7.06,104a52.72,52.72,0,0,1-6.18-.36,73.32,73.32,0,0,0,39.7,11.63" transform="translate(-0.88 -12.7)"/></svg>

After

Width:  |  Height:  |  Size: 702 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -0,0 +1,15 @@
<template>
<div class="w-full mb-10">
<slot />
</div>
</template>
<script>
export default {
name: "EnvGroup"
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<ul class="list-disc ml-10 text-gray-600 dark:text-dark-100 text-xl">
<slot/>
</ul>
</template>
<script>
export default {
name: "EnvList"
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,30 @@
<template>
<li>
{{ $t(title) }}:
<a class="duration-300 text-orange-400 font-medium border-b-2 border-opacity-0 hover:border-opacity-100 border-orange-400 border-solid" v-if="link" :href="link" target="_blank">{{ content }}</a>
<span v-else>{{ content }}</span>
</li>
</template>
<script>
export default {
name: "EnvListItem",
props:{
title: {
default: 'Title',
type: String
},
link: {
type: String
},
content: {
default: 'content',
type: String
},
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,22 @@
<template>
<h3 class="font-bold text-2xl md:text-4xl mb-2">
{{ $t(title) }}
<slot />
</h3>
</template>
<script>
export default {
name: "EnvTitle",
props:{
title: {
default: 'Title',
type: String
}
}
}
</script>
<style scoped>
</style>

View File

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

77
src/components/Footer.vue Normal file
View File

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

View File

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

187
src/components/Header.vue Normal file
View File

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

View File

@@ -0,0 +1,73 @@
<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-100",
type: String
},
link: {
default: "/",
type: String
}
},
setup(props: HomeLinkProps) {
const getColor = computed(() => `hover:bg-${props.color}-400 dark:hover:bg-${props.color}-600 active:bg-${props.color}-400 dark:active:bg-${props.color}-600`)
return {
getColor
}
}
}
</script>
<style scoped lang="scss">
.home-link:hover {
p {
@apply dark:text-white
}
.arrow {
transform: translateX(15px);
}
}
</style>

View File

@@ -1,37 +0,0 @@
<template>
<svg class="NuxtLogo" width="245" height="180" viewBox="0 0 452 342" xmlns="http://www.w3.org/2000/svg">
<path
d="M139 330l-1-2c-2-4-2-8-1-13H29L189 31l67 121 22-16-67-121c-1-2-9-14-22-14-6 0-15 2-22 15L5 303c-1 3-8 16-2 27 4 6 10 12 24 12h136c-14 0-21-6-24-12z"
fill="#00C58E"
/>
<path
d="M447 304L317 70c-2-2-9-15-22-15-6 0-15 3-22 15l-17 28v54l39-67 129 230h-49a23 23 0 0 1-2 14l-1 1c-6 11-21 12-23 12h76c3 0 17-1 24-12 3-5 5-14-2-26z"
fill="#108775"
/>
<path
d="M376 330v-1l1-2c1-4 2-8 1-12l-4-12-102-178-15-27h-1l-15 27-102 178-4 12a24 24 0 0 0 2 15c4 6 10 12 24 12h190c3 0 18-1 25-12zM256 152l93 163H163l93-163z"
fill="#2F495E"
/>
</svg>
</template>
<script lang="ts">
export default {
}
</script>
<style>
.NuxtLogo {
animation: 1s appear;
margin: auto;
}
@keyframes appear {
0% {
opacity: 0;
}
}
</style>

View File

@@ -0,0 +1,44 @@
<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"
>
{{ this.$t(title) }}
<slot />
</h1>
</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
}
}
}
</script>
<style scoped>
</style>

106
src/components/Post.vue Normal file
View File

@@ -0,0 +1,106 @@
<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>
</div>
<div class="self-end flex flex-wrap flex-col md:flex-row">
<div v-for="tag in tags"
class="my-1 md:my-0 ml-2 py-1 px-2 rounded font-semibold"
:class="lightBg ? 'bg-black text-white':'bg-white text-black'"
>
#{{ $t(tag) }}
</div>
</div>
</div>
</article>
</template>
<script lang="ts">
import {computed, useContext} from "@nuxtjs/composition-api";
interface PostProps {
title: string,
description: string,
reading_time: number,
date: string,
tags: [],
cover: string,
background_is_light: boolean
}
export default {
name: "Post",
props: {
title: {
type: String,
default: "New Post's title "
},
description: {
type: String,
default: "New Post's description"
},
reading_time: {
type: Number,
default: 0
},
date: {
type: String,
default: "Today"
},
tags: {
type: Array,
default: () => ["Tag1", "Tag2", "Tag3"],
},
cover: {
type: String,
default: "default.png"
},
lightBg: {
type: Boolean,
default: false
}
},
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`))
return {
getDate,
getBackGroundCover
}
}
}
</script>
<style scoped lang="scss">
.h-blog {
min-height: 20rem;
background-position: center;
background-size: cover;
@apply bg-opacity-50;
}
</style>

View File

@@ -1,7 +0,0 @@
# COMPONENTS
**This directory is not required, you can delete it if you don't want to use it.**
The components directory contains your Vue.js Components.
_Nuxt.js doesn't supercharge these components._

View File

@@ -10,9 +10,9 @@
</template>
<script lang="ts">
import { computed } from '@nuxtjs/composition-api'
import {computed} from '@nuxtjs/composition-api'
interface SkillProp {
interface SkillProps {
skill: string,
color: string,
cover: string
@@ -34,7 +34,7 @@ export default {
default: "logo.jpg"
}
},
setup(props: SkillProp) {
setup(props: SkillProps) {
const getColor = computed(() => `hover:bg-${props.color}-400`)
const getCoverLink = computed(() => require(`@/assets/images/skills/${props.cover}.png`))

View File

@@ -14,9 +14,9 @@
</template>
<script lang="ts">
import { computed } from '@nuxtjs/composition-api'
import {computed} from '@nuxtjs/composition-api'
interface WorkProp {
interface WorkProps {
title: string,
url: string,
cover: string,
@@ -43,7 +43,7 @@ export default {
default: 'white'
}
},
setup(props: WorkProp) {
setup(props: WorkProps) {
const formatLink = computed(() => props.url.replace('https://', '').replace('http://', ''))
const getColor = computed(() => `hover:bg-${props.color}-600`)
const getCoverLink = computed(() => `@/assets/images/works/${props.cover}.png`)

View File

@@ -13,9 +13,9 @@
</template>
<script lang="ts">
import { computed } from '@nuxtjs/composition-api'
import {computed} from '@nuxtjs/composition-api'
interface WorkSkillProp {
interface WorkSkillProps {
skill: string,
color: string,
cover: string
@@ -37,7 +37,7 @@ export default {
default: "logo.jpg"
}
},
setup(props: WorkSkillProp) {
setup(props: WorkSkillProps) {
const getColor = computed(() => `hover:bg-${props.color}-600`)
const getCoverLink = computed(() => require(`@/assets/images/skills/${props.cover}.png`))

View File

@@ -1,16 +0,0 @@
import {useContext} from "@nuxtjs/composition-api";
export const translate = (code: string) => {
const { $i18n } = useContext()
$i18n.t(code)
}
export const setLocale = async (locale: string) => {
const {$i18n} = useContext()
await $i18n.setLocale(locale)
}
export const getLocale = () =>{
const { $i18n } = useContext()
return $i18n.getBrowserLocale()
}