mirror of
https://github.com/ArthurDanjou/website-old.git
synced 2026-01-21 23:40:40 +01:00
💻 | Update all components with Composition API and TypeScript & Add images
This commit is contained in:
15
src/components/EnvGroup.vue
Normal file
15
src/components/EnvGroup.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div class="w-full mb-10">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "EnvGroup"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
15
src/components/EnvList.vue
Normal file
15
src/components/EnvList.vue
Normal 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>
|
||||
30
src/components/EnvListItem.vue
Normal file
30
src/components/EnvListItem.vue
Normal 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>
|
||||
22
src/components/EnvTitle.vue
Normal file
22
src/components/EnvTitle.vue
Normal 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>
|
||||
78
src/components/Experience.vue
Normal file
78
src/components/Experience.vue
Normal file
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<div class="flex flex-row mb-5">
|
||||
<div class="self-center flex h-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
77
src/components/Footer.vue
Normal 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>
|
||||
73
src/components/Formation.vue
Normal file
73
src/components/Formation.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<div class="flex flex-row mb-5">
|
||||
<div class="self-center flex h-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
187
src/components/Header.vue
Normal 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>
|
||||
73
src/components/HomeLink.vue
Normal file
73
src/components/HomeLink.vue
Normal 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>
|
||||
@@ -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>
|
||||
44
src/components/PageTitle.vue
Normal file
44
src/components/PageTitle.vue
Normal 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
106
src/components/Post.vue
Normal 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>
|
||||
@@ -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._
|
||||
@@ -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`))
|
||||
|
||||
|
||||
@@ -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`)
|
||||
|
||||
@@ -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`))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user