Working hardly

This commit is contained in:
2021-08-17 15:32:55 +02:00
parent e8484f98d5
commit adb052d1de
33 changed files with 988 additions and 767 deletions

2
.npmrc
View File

@@ -1,2 +0,0 @@
shamefully-hoist=true
ignore-workspace-root-check=true

View File

@@ -6,6 +6,7 @@ import arch from './settings/Arch'
import plugins from './settings/Plugins'
import css from './settings/Style'
import configs from './settings/RuntimeConfig'
import {NuxtConfig} from "@nuxt/types";
const config = {
head,
@@ -16,6 +17,6 @@ const config = {
css,
buildModules,
...configs,
}
} as NuxtConfig
export default config

View File

@@ -10,8 +10,9 @@
"dependencies": {
"@nuxt/content": "^1.14.0",
"@nuxtjs/axios": "^5.13.6",
"@nuxtjs/composition-api": "0.23.4",
"@nuxtjs/composition-api": "0.26.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",
@@ -19,20 +20,18 @@
"@nuxtjs/sitemap": "^2.4.0",
"@nuxtjs/universal-storage": "^0.5.9",
"axios": "^0.21.1",
"core-js": "^3.14.0",
"nuxt": "^2.15.7",
"nuxt-i18n": "^6.27.1",
"prism-themes": "^1.7.0",
"sass": "^1.35.1",
"vuex": "^3.6.2",
"windicss": "^3.1.3"
"core-js": "^3.16.1",
"nuxt": "^2.15.8",
"prism-themes": "^1.8.0",
"sass": "^1.37.5",
"windicss": "^3.1.7"
},
"devDependencies": {
"@nuxt/types": "^2.15.7",
"@nuxt/types": "^2.15.8",
"@nuxt/typescript-build": "^2.1.0",
"@nuxtjs/color-mode": "^2.0.10",
"markdown-it-prism": "^2.1.6",
"nuxt-windicss": "^1.1.1",
"@nuxtjs/color-mode": "^2.1.1",
"markdown-it-prism": "^2.1.8",
"nuxt-windicss": "^1.2.3",
"sass-loader": "10.1.1"
}
}

View File

@@ -89,7 +89,7 @@ const sentry = {
export default [
['@nuxtjs/axios', axios],
['nuxt-i18n', i18n],
['@nuxtjs/i18n', i18n],
['@nuxt/content', content],
['@nuxtjs/universal-storage', storage],
['@nuxtjs/robots', robots],

View File

@@ -33,7 +33,7 @@ export default defineComponent({
.catch((error) => {
$sentry.captureEvent(error)
});
})
}, 'infos')
return {
info

View File

@@ -37,6 +37,6 @@
<script lang="ts">
export default {
name: "AdPreview"
name: "AdHome"
}
</script>

View File

@@ -1,28 +1,24 @@
<template>
<div
v-if="announce"
class="h-12 flex justify-center items-center"
:class="[getBackgroundColor, getHoverColor]"
class="p-4 duration-300 flex justify-center items-center text-center"
:class="[getHoverColor, getBackgroundColor]"
>
{{ announce.translation.code }}
{{ $t(announce.message.code) }}
<img
v-if="announce.file"
:src="`https://athena.arthurdanjou.fr/files/${announce.file}`"
alt="Announce Cover File"
>
</div>
<div v-else class="p-4 duration-300 flex justify-center items-center text-center bg-black dark:bg-white text-white dark:text-black">
{{ $t('loading') }}
</div>
</template>
<script lang="ts">
import {computed, ref, useAsync, useContext} from "@nuxtjs/composition-api";
import {Translation} from "~/types/types";
interface Announce {
color: string,
hover_color: string,
translation: Translation
file: null
}
import {Announce} from "~/types/types";
export default {
name: "Announcement",
@@ -52,9 +48,9 @@ export default {
})
const getHoverColor = computed(() => {
switch (announce.value!.color) {
switch (announce.value!.hover_color) {
case 'gray': {
return 'hover:bg-gray-600'
return 'hover:bg-gray-800 dark:hover:bg-gray-300'
}
}
})
@@ -62,7 +58,7 @@ export default {
return {
announce,
getBackgroundColor,
getHoverColor
getHoverColor,
}
}
}

View File

@@ -84,7 +84,7 @@ export default defineComponent({
const {$axios, $sentry} = useContext()
const form = ref<Form>({} as Form)
const handleForm = async () => {
const response = await $axios.post('form',
const response = await $axios.post('/api/form',
{
email: form.value.email,
name: form.value.name,

View File

@@ -1,70 +1,150 @@
<template>
<footer class="footer w-full border-t-2 border-solid border-gray-200 px-4 xl:px-32 dark:border-gray-800 mb-26 md:mb-0">
<div class="flex flex-col-reverse md:flex-row justify-between pt-4 items-center">
<div class="inline flex space-x-4">
<a class="link font-semibold" href="https://twitch.com/ArthurDanjou" target="_blank" rel="noopener noreferrer">
<TwitchIcon /> <span>Twitch</span>,
</a>
<a class="link font-semibold" href="https://github.com/ArthurDanjou" target="_blank" rel="noopener noreferrer">
<GithubIcon /> <span>Github</span>,
</a>
<a class="link font-semibold" href="https://twitter.com/ArthurDanj" target="_blank" rel="noopener noreferrer">
<TwitterIcon /> <span>Twitter</span>,
</a>
<a class="link font-semibold" href="mailto:contact@arthurdanjou.fr" target="_blank" rel="noopener noreferrer">
<MailIcon /> <span>Mail</span>
</a>
<footer class="footer w-full mt-20">
<div class="p-8 pb-0">
<div class="lg:flex justify-evenly">
<div class="lg:w-1/3">
<div class="flex">
<Logo />
</div>
<div class="flex space-x-4 mb-4 md:mb-0">
<nuxt-link class="link font-semibold" to="/env">
<span>{{ $t('header.env') }}</span>,
</nuxt-link>
<nuxt-link class="link font-semibold" to="/guestbook">
<span>{{ $t('header.guestbook') }}</span>,
</nuxt-link>
<nuxt-link class="link font-semibold" to="/contact">
<span>{{ $t('header.contact') }}</span>,
</nuxt-link>
<nuxt-link class="link font-semibold" to="/newsletter">
<span>{{ $t('header.newsletter') }}</span>
<div class="my-8">
<p class="text-justify">
{{ $t('footer.description') }}
</p>
<div class="mt-4">
<nuxt-link to="/contact" class="text-red-400 border-b-2 border-gray-200 dark:border-gray-700 hover:border-red-400 duration-300">
{{ $t(hiring_message) }}
</nuxt-link>
</div>
</div>
<div class="text-center my-4">
<p>
<div class="social-links flex space-x-4 mb-8">
<a target="_blank" href="https://twitter.com/ArthurDanj" rel="noopener noreferrer">
<TwitterIcon />
</a>
<a target="_blank" href="https://github.com/ArthurDanjou" rel="noopener noreferrer">
<GithubIcon />
</a>
<a target="_blank" href="https://www.polywork.com/arthurdanjou" rel="noopener noreferrer">
<PolyworkIcon />
</a>
<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">
<DiscordIcon />
</a>
<a target="_blank" href="mailto:contact@arthurdanjou.fr" rel="noopener noreferrer">
<MailIcon />
</a>
</div>
</div>
<div class="lg:ml-32 lg:w-1/3">
<h1 class="font-bold mb-4 text-lg underline">
{{ $t('footer.links') }}
</h1>
<div class="flex flex-col mb-8 space-y-2 lg:space-y-4 font-medium">
<div class="link">
<nuxt-link to="/">
{{ $t('header.home') }}
</nuxt-link>
</div>
<div class="link">
<nuxt-link to="/about">
{{ $t('header.about') }}
</nuxt-link>
</div>
<div class="link">
<nuxt-link to="/blog">
{{ $t('header.blog') }}
</nuxt-link>
</div>
<div class="link">
<nuxt-link to="/projects">
{{ $t('header.projects') }}
</nuxt-link>
</div>
<div class="link">
<nuxt-link to="/services">
{{ $t('header.services') }}
</nuxt-link>
</div>
<div class="link">
<nuxt-link to="/env">
{{ $t('header.env') }}
</nuxt-link>
</div>
<div class="link">
<nuxt-link to="/guestbook">
{{ $t('header.guestbook') }}
</nuxt-link>
</div>
<div class="link">
<nuxt-link to="/newsletter">
{{ $t('header.newsletter') }}
</nuxt-link>
</div>
<div class="link">
<nuxt-link to="/contact">
{{ $t('header.contact') }}
</nuxt-link>
</div>
</div>
</div>
</div>
<div class="text-center border-t-2 border-gray-200 dark:border-gray-800 py-8 lg:flex lg:flex-row-reverse justify-between">
<div>
{{ $t('footer.credits') }}
<a class="link font-semibold" target="_blank" href="https://nuxtjs.org" rel="noopener noreferrer">
<a class="social font-semibold" target="_blank" href="https://nuxtjs.org" rel="noopener noreferrer">
<NuxtIcon />
<span>NuxtJS</span>
</a>
{{ $t('footer.credits_separator_and') }}
<a class="link font-semibold" target="_blank" href="https://adonisjs.com" rel="noopener noreferrer">
{{ $t('footer.credits_separator') }}
<a class="social font-semibold" target="_blank" href="https://adonisjs.com" rel="noopener noreferrer">
<AdonisIcon />
<span>AdonisJS</span>
</a>
{{ $t('footer.credits_separator') }} <span>Arthur DANJOU</span>
</p>
<p>{{ $t('footer.copyrights', { date: getDate }) }}</p>
</div>
<p class="mt-4 lg:mt-0">{{ $t('footer.copyrights', { date: getDate }) }}</p>
</div>
</div>
</footer>
</template>
<script lang="ts">
import {computed, defineComponent, ref, useContext} from "@nuxtjs/composition-api";
import {computed, defineComponent, ref, useAsync, useContext, useRouter, useStore} from "@nuxtjs/composition-api";
import {State} from "~/types/types";
export default defineComponent({
name: "Footer",
setup() {
const {$colorMode} = useContext()
const {$colorMode, $axios, $sentry, app} = useContext()
const isDarkMode = computed(() => {
return $colorMode.preference === 'dark'
})
const getDate = ref(new Date().getFullYear())
const hiring_message = ref("")
useAsync(async () => {
const request = await $axios.get('/api/informations', {
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`
}
})
if (request.status === 200) {
hiring_message.value = request.data.informations.translation.code
} else {
app.error({statusCode: 500})
$sentry.captureEvent(request.data)
}
})
const store = useStore<State>()
const route = computed(() => store.state.route)
return {
getDate,
isDarkMode
isDarkMode,
hiring_message
}
}
})
@@ -72,7 +152,7 @@ export default defineComponent({
<style scoped lang="scss">
.footer {
.link {
.social {
span {
@apply border-b-2 border-gray-200 dark:border-gray-700 duration-300;
}
@@ -80,5 +160,14 @@ export default defineComponent({
@apply border-indigo-600
}
}
.link {
a {
@apply border-b-2 border-transparent duration-300;
&:hover {
@apply border-indigo-600;
}
}
}
}
</style>

View File

@@ -98,7 +98,7 @@ export default defineComponent({
const alreadySent = ref(false)
const hasAlreadySignMessage = async (id: number) => {
const response = await $axios.get(`/guestbook/${id}`, {
const response = await $axios.get(`/api/guestbook/${id}`, {
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`
}

View File

@@ -49,7 +49,7 @@ export default defineComponent({
const month = realMonth.toString().length == 2 ? realMonth.toString() : `0${realMonth.toString()}`
const minutes = date.getMinutes().toString().length == 2 ? date.getMinutes() : `0${date.getMinutes()}`
const hours = date.getHours().toString().length == 2 ? date.getHours() : `0${date.getHours()}`
return `${date.getDate()} ${i18n.t(`month.${month}`)} ${date.getFullYear()} at ${hours}:${minutes}`
return `${date.getDate()} ${i18n.t(`month.${month}`)} ${date.getFullYear()} ${i18n.t('guestbook.at')} ${hours}:${minutes}`
})
return {

View File

@@ -1,22 +1,20 @@
<template>
<header class="hidden md:block dark:bg-black dark:text-white sticky z-50 top-0 left-0 bg-white w-full duration-400"
<header class="hidden xl:block dark:bg-black dark:text-white z-50 sticky top-0 left-0 bg-white w-full duration-400"
:class="scrollPosition > 65 ? 'shadow-md dark:shadow-white h-16 lg:h-20' : 'h-20 lg:h-24'">
<div class="header-container z-index-50 flex justify-between items-center h-full px-5 xl:px-32">
<nuxt-link to="/">
<img src="~/assets/images/logo-header.png" alt="Logo Circle" class="h-10 left cursor-pointer duration-500"/>
</nuxt-link>
<Logo />
<nav class="right flex flex-col md:flex-row items-center hidden md:inline-block">
<div class="flex text-lg">
<nuxt-link class="nav-link" to="/about">
<nuxt-link class="nav-link" to="/about" :class="{ 'link-active': isWindow('about') }">
{{ $t('header.about') }}
</nuxt-link>
<nuxt-link class="nav-link" to="/blog">
<nuxt-link class="nav-link" to="/blog" :class="{ 'link-active': isWindow('blog') }">
{{ $t('header.blog') }}
</nuxt-link>
<nuxt-link class="nav-link" to="/projects">
<nuxt-link class="nav-link" to="/projects" :class="{ 'link-active': isWindow('projects') }">
{{ $t('header.projects') }}
</nuxt-link>
<nuxt-link class="nav-link" to="/contact">
<nuxt-link class="nav-link" to="/contact" :class="{ 'link-active': isWindow('contact') }">
{{ $t('header.contact') }}
</nuxt-link>
</div>
@@ -44,14 +42,17 @@
<script lang="ts">
import {
computed,
defineComponent,
onMounted,
onUnmounted,
ref,
useAsync,
useContext,
useRouter
useRouter,
useStore
} from "@nuxtjs/composition-api";
import {State} from "~/types/types";
export default defineComponent({
name: "Header",
@@ -83,11 +84,20 @@ export default defineComponent({
}
})
const store = useStore<State>()
const route = computed(() => store.state.route)
const isWindow = (loc: string) => {
if (loc === '') return route.value === "/"
else return route.value.includes(loc)
}
return {
scrollPosition,
changeColorMode,
updateScroll,
changeLanguage,
isWindow
}
}
})
@@ -95,10 +105,14 @@ export default defineComponent({
<style scoped lang="scss">
.nav-link {
@apply font-medium cursor-pointer duration-300 mx-4 border-b-2 border-transparent hover:(border-indigo-600);
@apply font-medium cursor-pointer duration-500 mx-4 border-b-2 border-transparent hover:(border-indigo-600);
}
.navbar-bottom-items li {
transition: all .2s ease-in-out;
}
.link-active {
@apply text-indigo-600
}
</style>

18
src/components/Logo.vue Normal file
View File

@@ -0,0 +1,18 @@
<template>
<nuxt-link class="profile ml-4 flex items-center" to="/">
<img class="h-12 w-12 duration-500" src="@/assets/images/photo-rounded.png" alt="Photo of me" />
<h1 class="ml-4 font-bold text-lg">Arthur Danjou</h1>
</nuxt-link>
</template>
<script>
export default {
name: "Logo"
}
</script>
<style lang="scss">
.profile:hover img {
@apply transform rotate-360;
}
</style>

View File

@@ -1,41 +1,31 @@
<template>
<div
class="w-full z-100 fixed bottom-0 left-0 md:hidden duration-500"
:class="{'opened': isOpened}"
class="xl:hidden fixed z-50 top-auto bottom-0 w-full md:w-2/3 md:left-1/2 p-4 transition-all duration-500 transform md:-translate-x-1/2"
:class="{'-translate-y-8 translate-x-9/12 sm:translate-x-1/2 xl:translate-x-0': opened}"
>
<ul
class="bg-gray-200 dark:bg-gray-800 m-4 rounded-3xl dark:text-white text-sm flex items-center justify-around h-20 navbar-bottom-items"
>
<nuxt-link to="/" class="w-1/5">
<li class="h-full w-full font-medium flex flex-col items-center justify-center">
<nav class="flex justify-evenly py-4 bg-gray-200 dark:bg-gray-700 rounded-3xl dark:text-white text-sm overflow-hidden">
<nuxt-link to="/" class="relative font-medium">
<HomeIcon :active="isWindow('')"/>
{{ debug }}
</li>
</nuxt-link>
<nuxt-link to="/about" class="w-1/5">
<li class="font-medium flex flex-col items-center justify-center">
<nuxt-link to="/about" class="relative font-medium">
<UserIcon :active="isWindow('/about')"/>
</li>
</nuxt-link>
<nuxt-link to="/blog" class="w-1/5">
<li class="font-medium flex flex-col items-center justify-center">
<nuxt-link to="/blog" class="relative font-medium">
<BookIcon :active="isWindow('/blog')"/>
</li>
</nuxt-link>
<nuxt-link to="/projects" class="w-1/5">
<li class="font-medium flex flex-col items-center justify-center">
<nuxt-link to="/projects" class="relative font-medium">
<LightbulbIcon :active="isWindow('/projects')"/>
</li>
</nuxt-link>
<li @click='toggleMenu' class="w-1/5 flex flex-col items-center justify-center cursor-pointer">
<MenuIcon :type="getMenuIconType"/>
</li>
</ul>
<button @click.prevent='toggleMenu' class="font-medium cursor-pointer">
<CrossIcon v-if="opened" />
<MenuIcon v-else :type="getMenuIconType"/>
</button>
</nav>
</div>
</template>
<script lang="ts">
import {computed, defineComponent, useRouter, useStore} from "@nuxtjs/composition-api";
import {computed, defineComponent, ref, useRouter, useStore, watch} from "@nuxtjs/composition-api";
import {State} from "~/types/types";
const PAGE_TYPE = {
@@ -45,43 +35,42 @@ const PAGE_TYPE = {
export default defineComponent({
name: "MobileNavbar",
setup () {
const $router = useRouter()
const debug = computed(() => $router.currentRoute.path)
const isWindow = (loc: string) => {
if (loc === '') return $router.currentRoute.path === "/"
else return $router.currentRoute.path.includes(loc)
}
const getMenuIconType = computed(() => PAGE_TYPE[$router.currentRoute.path.split('/')[1]] || 0)
const store = useStore<State>()
const toggleMenu = () => {
window.scrollTo({
top: 0,
})
store.commit('TOGGLE_OPENED', !store.state.opened)
const route = computed(() => store.state.route)
const isWindow = (loc: string) => {
if (loc === '') return route.value === "/"
else return route.value.includes(loc)
}
const getMenuIconType = computed(() => PAGE_TYPE[route.value.split('/')[1]] || 0)
const toggleMenu = () => {
store.commit('TOGGLE_OPENED', !store.state.opened)
if (store.state.opened) {
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)
}
}
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)
})
const isOpened = computed(() => store.state.opened)
return {
isWindow,
toggleMenu,
isOpened,
getMenuIconType,
debug
opened: computed(() => store.state.opened),
getMenuIconType
}
}
})
</script>
<style scoped lang="scss">
.opened {
@apply transform translate-x-9/12 scale-90 -translate-y-10 duration-500;
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<nuxt-link :to="`/blog/${slug}`" rel="noreferrer noopener">
<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})` }">

View File

@@ -1,5 +1,5 @@
<template>
<a :href="url" target="_blank" rel="noopener noreferrer">
<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})` }">

View File

@@ -10,7 +10,7 @@
</p>
</div>
<div class="my-8 lg:flex w-full lg:space-x-8 flex flex-wrap justify-center">
<div v-for="project in projects">
<div v-for="project in projects" class="mb-4">
<Project
:title="project.title"
:cover="project.cover"

View File

@@ -1,7 +1,12 @@
<template>
<div class="md:hidden w-full min-w-screen">
<div class="bg-gray-100 dark:bg-gray-900 min-h-screen duration-500 absolute top-0 left-0 right-0 py-4 pr-20 pl-4 flex items-center">
<nav class="w-auto">
<div class="relative w-full min-w-screen xl:overflow-auto">
<div
class="min-h-screen bg-gray-100 dark:bg-gray-900 xl:hidden pl-4 pr-20 py-4 transition-all duration-500 duration-500 absolute top-0 left-0 right-0 flex items-center"
>
<nav
id="nav"
class="w-auto"
>
<div class="mb-8">
<div class="flex justify-between mb-4">
<div @click="closeMenu" class="flex justify-center items-center cursor-pointer cross text-sm">
@@ -26,10 +31,7 @@
</ul>
</div>
</div>
<nuxt-link class="profile ml-4 flex items-center" to="/">
<img class="h-12 w-12 duration-500" src="@/assets/images/photo-rounded.png" alt="Photo of me" />
<h1 class="ml-4 font-bold text-lg">Arthur Danjou</h1>
</nuxt-link>
<Logo />
</div>
<div class="w-auto flex">
<div class="flex flex-col ml-4 mb-8 space-y-1.5 font-bold text-lg">
@@ -38,7 +40,7 @@
{{ $t('header.home') }}
</nuxt-link>
</div>
<div class="nav-link" :class="{ 'link-active': isWindow('') }">
<div class="nav-link" :class="{ 'link-active': isWindow('about') }">
<nuxt-link to="/about">
{{ $t('header.about') }}
</nuxt-link>
@@ -68,6 +70,11 @@
{{ $t('header.guestbook') }}
</nuxt-link>
</div>
<div class="nav-link" :class="{ 'link-active': isWindow('newsletter') }">
<nuxt-link to="/newsletter">
{{ $t('header.newsletter') }}
</nuxt-link>
</div>
<div class="nav-link" :class="{ 'link-active': isWindow('contact') }">
<nuxt-link to="/contact">
{{ $t('header.contact') }}
@@ -75,7 +82,7 @@
</div>
</div>
</div>
<div class="social-links flex justify-between space-x-1">
<div class="social-links flex justify-between space-x-0.5">
<a target="_blank" href="https://twitter.com/ArthurDanj" rel="noopener noreferrer">
<TwitterIcon />
</a>
@@ -101,7 +108,14 @@
</template>
<script lang="ts">
import {defineComponent, useAsync, useContext, useRouter, useStore} from "@nuxtjs/composition-api";
import {
computed,
defineComponent,
useAsync,
useContext,
useRouter,
useStore
} from "@nuxtjs/composition-api";
import {State} from "~/types/types";
export default defineComponent({
@@ -121,21 +135,27 @@ export default defineComponent({
}
})
const isWindow = (loc: string) => {
if (loc === '') return $router.currentRoute.path === "/"
else return $router.currentRoute.path.includes(loc)
}
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)
}
const route = computed(() => store.state.route)
const isWindow = (loc: string) => {
if (loc === '') return route.value === "/"
else return route.value.includes(loc)
}
return {
isWindow,
changeColorMode,
changeLanguage,
closeMenu
closeMenu,
opened: computed(() => store.state.opened),
isWindow
}
}
})
@@ -146,11 +166,7 @@ export default defineComponent({
@apply transform scale-140;
}
.profile:hover img {
@apply transform rotate-360;
}
.nav-link a, .link-active a {
.nav-link a {
@apply duration-300 border-b-2 border-transparent;
&:hover {
@@ -158,9 +174,13 @@ export default defineComponent({
}
}
.link-active a {
@apply text-indigo-600;
}
.social-links a {
svg {
@apply h-8 w-8 duration-300
@apply h-6 w-6 duration-300
}
&:hover svg {

View File

@@ -4,7 +4,7 @@
<g fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 12h18"/>
<path d="M3 6h18"/>
<path d="M3 18h18/"/>
<path d="M3 18h18"/>
</g>
</svg>
<svg v-else-if="type === 1" class="inline" width="2.5em" height="2.5em" viewBox="0 0 48 48" focusable="false">

View File

@@ -7,6 +7,14 @@
"begin_date": "04-2015",
"end_date": "Today"
},
{
"slug": "bac",
"title": "formations.bac.title",
"description": "formations.bac.description",
"location": "France",
"begin_date": "09-2020",
"end_date": "07-2021 "
},
{
"slug": "dnb",
"title": "formations.dnb.title",
@@ -14,13 +22,5 @@
"location": "France",
"begin_date": "09-2017",
"end_date": "09-2018"
},
{
"slug": "bac",
"title": "formations.bac.title",
"description": "formations.bac.description",
"location": "France",
"begin_date": "09-2020",
"end_date": "Today"
}
]

View File

@@ -9,7 +9,7 @@
},
{
"slug": "ares",
"title": "ares",
"title": "Ares",
"description": "works.ares",
"url": "https://arthurdanjou.fr",
"cover": "ares.png",

View File

@@ -1,34 +1,46 @@
<template>
<div>
<div class="relative">
<SideMenu />
<div class="relative w-full overflow-hidden">
<div
class="z-50 relative top-0 left-0 w-full duration-500 h-1/2"
:class="{'opened': opened}"
:style="`max-height: ${height}px`"
id="slider"
class="relative xl:static shadow-2xl overflow-hidden transform transition-all duration-500"
:class="{'rounded-lg xl:rounded-none scale-90 md:scale-70 lg:scale-60 xl:scale-100 translate-x-9/12 sm:translate-x-4/12 lg:translate-x-3/12 xl:translate-x-0': opened}"
:style="opened ? `max-height: ${height}px` : 'max-height: none'"
:tabindex="opened ? -1 : 0"
>
<div
@click.prevent="closeMenu"
class="min-h-screen relative z-50 bg-white dark:bg-black w-full min-w-screen pb-20 xl:pb-0 duration-300"
:class="{'cursor-pointer': opened}"
>
<div @click="closeMenu" class="z-50 bg-white dark:bg-black overflow-hidden overflow-x-hidden w-full min-w-screen" :class="{'cursor-pointer': opened}">
<Announcement />
<Header />
<Nuxt class="z-10 pt-16 lg:pt-24 content"/>
<Footer />
</div>
</div>
</div>
<MobileNavbar />
</div>
</template>
<script lang="ts">
import {computed, onMounted, ref, useStore} from "@nuxtjs/composition-api";
import {computed, onMounted, ref, useRouter, useStore} from "@nuxtjs/composition-api";
import {State} from "~/types/types";
export default {
setup() {
const store = useStore<State>()
const $router = useRouter()
const opened = computed(() => store.state.opened)
$router.afterEach(() => {
store.commit('SET_ROUTE', $router.currentRoute.path)
})
const closeMenu = () => {
store.commit('TOGGLE_OPENED', false)
document.getElementById('nav')!.classList.remove('z-50')
}
const height = ref(0)
@@ -37,16 +49,10 @@ export default {
})
return {
opened,
opened: computed(() => store.state.opened),
closeMenu,
height
height,
}
}
}
</script>
<style scoped lang="scss">
.opened {
@apply rounded-lg overflow-hidden overflow-x-hidden transform scale-90 translate-x-9/12 transition-all duration-500;
}
</style>

View File

@@ -1,4 +1,6 @@
export default {
import axios from "axios";
const translations = {
header: {
home: 'Home',
about: 'About',
@@ -204,7 +206,8 @@ export default {
placeholder: 'Your message...',
sign: 'Sign',
error: 'Error while sending your message ❌',
success: 'Thank you for your message 😉'
success: 'Thank you for your message 😉',
at: 'at'
},
newsletter: {
@@ -287,5 +290,24 @@ export default {
ares: 'Ares is my personal website creating a single point of contact',
erisium: 'Erisium is a french minecraft mini-game server.',
linkyjs: 'LinkyJS is my custom and Open-Source url shortener'
},
loading: 'Loading...'
}
export default async function () {
let informations = {}
const response = await axios.get('https://athena.arthurdanjou.fr/translations', {
headers: {
authorization: `Bearer ${process.env.API_TOKEN}`
}
})
response.data.translations.map(({ code, english }: any) => {
informations = { ...informations, [code]: english }
})
return {
...informations,
...translations
}
}

View File

@@ -1,4 +1,7 @@
export default {
import axios from "axios";
import {Translation} from "~/types/types";
const translations = {
header: {
home: 'Accueil',
about: 'A Propos',
@@ -15,6 +18,10 @@ export default {
close: 'Fermer le menu'
},
services: {
description: 'Je fourni tout ce dont vous avez besoin pour créer votre site internet parfait'
},
part: {
about: 'A propos',
contact: 'Me contacter',
@@ -22,14 +29,16 @@ export default {
blog: 'Mon blog',
env: 'Mon environnement',
guestbook: "Mon livre d'or",
newsletter: 'Ma newsletter'
newsletter: 'Ma newsletter',
services: 'Mes services'
},
footer: {
credits: 'Développé et conçu avec ❤️ en utilisant',
credits_separator: 'par',
credits_separator_and: 'et',
copyrights: '© Copyright {date} - Tous droits réservés'
description: 'Développeur Web et Logiciel, mais également étudiant en Mathématiques et en Physique. Je développe des sites internet',
links: 'Liens rapides',
credits: 'Développé avec',
credits_separator: 'et',
copyrights: '© {date} Arthur Danjou - Tous droits réservés'
},
error: {
@@ -208,7 +217,8 @@ export default {
placeholder: 'Votre message...',
sign: 'Signer',
error: "Erreur lors de l'envoi de votre message ❌",
success: 'Merci pour votre message 😉'
success: 'Merci pour votre message 😉',
at: 'à'
},
newsletter: {
@@ -291,5 +301,24 @@ export default {
ares: 'Ares est mon site personnel créant un point de contact unique.',
erisium: 'Erisium est un serveur minecraft francophone de mini-jeux.',
linkyjs: "LinkyJS est mon raccourcisseur d'url personnalisé et Open-Source."
},
loading: 'Chargement...'
}
export default async function () {
let informations = {}
const response = await axios.get('https://athena.arthurdanjou.fr/translations', {
headers: {
authorization: `Bearer ${process.env.API_TOKEN}`
}
})
response.data.translations.map(({ code, french }: any) => {
informations = { ...informations, [code]: french }
})
return {
...informations,
...translations
}
}

View File

@@ -9,19 +9,6 @@
{{ $t('contact.why.description') }}
</h3>
</section>
<section class="w-full lg:w-3/4 mb-10 mt-4 text-justify">
<h1 class="font-bold text-gray-700 text-xl md:text-3xl my-4 dark:text-gray-400">
{{ $t('contact.available.title') }}
</h1>
<h3 class="text-lg md:text-xl">
{{ $t('contact.available.description') }}
</h3>
<div class="text-lg md:text-xl my-4 text-indigo-600">
{{ $t('contact.available.start') }}
<span v-if="info && info.hiring.status && info.hiring.color" class="py-1 px-2 font-bold rounded-full m-0.5" :class="getColor">{{ $t('hiring.status.' + info.hiring.status) }}</span>
{{ $t('contact.available.end') }}
</div>
</section>
<ContactForm class="w-full"/>
</main>
</template>

View File

@@ -1,5 +1,5 @@
<template>
<main v-if="projects" class="work flex flex-col items-center px-4 xl:px-32">
<main v-if="projects" class="flex flex-col items-center px-4 xl:px-32">
<PageTitle title="part.projects" />
<h1 v-if="projects.length === 0" class="text-xl font-bold text-center my-8 w-full">{{ $t('projects.no_project') }}</h1>
<div v-else class="flex flex-col justify-around items-center py-10 w-full">

18
src/pages/services.vue Normal file
View File

@@ -0,0 +1,18 @@
<template>
<main class="flex flex-col items-center px-4 xl:px-32">
<PageTitle title="part.services" />
<p class="text-justify text-gray-700 dark:text-gray-400 text-xl my-8">{{ $t('services.description') }}</p>
</main>
</template>
<script lang="ts">
import {defineComponent} from "@nuxtjs/composition-api";
export default defineComponent({
name: "services"
})
</script>
<style scoped>
</style>

2
src/plugins/main.ts Executable file → Normal file
View File

@@ -1 +1 @@
import 'windi.css'
import 'virtual:windi.css'

View File

@@ -1,15 +1,18 @@
import {GetterTree, MutationTree} from "vuex";
export const state = () => ({
opened: false
opened: false,
route: '/'
})
export type RootState = ReturnType<typeof state>
export const getters: GetterTree<RootState, RootState> = {
opened: state => state.opened,
route: state => state.route
}
export const mutations: MutationTree<RootState> = {
TOGGLE_OPENED: (state, opened: boolean) => (state.opened = opened),
SET_ROUTE: (state, route: string) => (state.route = route)
}

View File

@@ -63,7 +63,9 @@
"@nuxtjs/axios",
"@nuxtjs/sentry",
"@nuxtjs/composition-api",
"nuxt-i18n"
"@nuxtjs/i18n",
"@nuxtjs/color-mode",
"@nuxtjs/universal-storage"
] /* Type declaration files to be included in compilation. */,
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,

36
types/index.d.ts vendored
View File

@@ -1,36 +0,0 @@
import { NuxtAxiosInstance } from '@nuxtjs/axios'
import VueI18n, {IVueI18n} from "vue-i18n";
import {ColorModeInstance} from "@nuxtjs/color-mode/types/color-mode";
import {NuxtApp} from "@nuxt/types/app";
import {NuxtStorage} from "@nuxtjs/universal-storage";
import {NuxtOptionsRouter} from "@nuxt/types/config/router";
declare module 'vue/types/vue' {
interface Vue {
$axios: NuxtAxiosInstance,
i18n: VueI18n & IVueI18n
}
}
declare module '@nuxt/types' {
interface NuxtAppOptions {
$axios: NuxtAxiosInstance,
i18n: VueI18n & IVueI18n
}
interface Context {
$axios: NuxtAxiosInstance,
i18n: VueI18n & IVueI18n
$colorMode: ColorModeInstance,
app: NuxtApp,
$storage: NuxtStorage
}
}
declare module 'vuex/types/index' {
interface Store<S> {
$axios: NuxtAxiosInstance,
i18n: VueI18n & IVueI18n
}
}

View File

@@ -76,7 +76,15 @@ interface Translation {
}
interface State {
opened: boolean
opened: boolean,
route: string
}
export { Form, InfoData, Skill, Experience, Formation, Post, Tag, Project, GuestbookForm, NewsletterForm, Translation, State }
interface Announce {
color: string,
hover_color: string,
translation: Translation
file: null
}
export { Form, InfoData, Skill, Experience, Formation, Post, Tag, Project, GuestbookForm, NewsletterForm, Translation, State, Announce }

1054
yarn.lock

File diff suppressed because it is too large Load Diff