mirror of
https://github.com/ArthurDanjou/artsite.git
synced 2026-01-14 15:54:13 +01:00
Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -84,6 +84,7 @@ const socialsList = [
|
||||
/>
|
||||
</UTooltip>
|
||||
</UDropdownMenu>
|
||||
<ThemeSwitcher />
|
||||
</nav>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
61
app/components/home/Education.vue
Normal file
61
app/components/home/Education.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<script lang="ts" setup>
|
||||
const { education } = await useContent()
|
||||
|
||||
const formatDate = (iso?: string) => {
|
||||
if (!iso) return 'Present'
|
||||
const d = new Date(iso)
|
||||
if (Number.isNaN(d.getTime())) return iso
|
||||
return useDateFormat(d, 'MMM YYYY', { locales: 'en-US' }).value
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
v-if="education && education.length"
|
||||
class="my-8 space-y-6"
|
||||
aria-labelledby="education-title"
|
||||
>
|
||||
<h2
|
||||
id="education-title"
|
||||
class="sr-only"
|
||||
>
|
||||
Education
|
||||
</h2>
|
||||
|
||||
<div class="grid gap-4 grid-cols-1">
|
||||
<UCard
|
||||
v-for="item in education"
|
||||
:key="item.id"
|
||||
variant="outline"
|
||||
color="neutral"
|
||||
>
|
||||
<div>
|
||||
<h3 class="text-lg md:text-xl font-semibold tracking-tight">
|
||||
{{ item.degree ?? item.title }}
|
||||
</h3>
|
||||
<p class="text-sm text-neutral-600 dark:text-neutral-400 mb-2">
|
||||
{{ item.institution }}
|
||||
</p>
|
||||
<p class="text-sm text-neutral-700 dark:text-neutral-300 flex flex-wrap items-center gap-2">
|
||||
<span class="font-medium">Dates:</span>
|
||||
<span>{{ formatDate(item.startDate) }} — {{ formatDate(item.endDate) }}</span>
|
||||
<span
|
||||
v-if="item.duration"
|
||||
class="text-neutral-500"
|
||||
>({{ item.duration }})</span>
|
||||
</p>
|
||||
<p
|
||||
class="text-sm text-neutral-700 dark:text-neutral-300 mt-1"
|
||||
>
|
||||
<span class="font-medium">Location:</span> {{ item.location }}
|
||||
</p>
|
||||
<p
|
||||
class="text-sm text-neutral-700 dark:text-neutral-300 mt-3"
|
||||
>
|
||||
{{ item.description }}
|
||||
</p>
|
||||
</div>
|
||||
</UCard>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
100
app/components/home/Experiences.vue
Normal file
100
app/components/home/Experiences.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<script lang="ts" setup>
|
||||
const { experiences } = await useContent()
|
||||
|
||||
const formatDate = (iso?: string) => {
|
||||
if (!iso) return 'Present'
|
||||
const d = new Date(iso)
|
||||
if (Number.isNaN(d.getTime())) return iso
|
||||
return useDateFormat(d, 'MMM YYYY', { locales: 'en-US' }).value
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
v-if="experiences && experiences.length"
|
||||
class="my-8 space-y-6"
|
||||
aria-labelledby="experiences-title"
|
||||
>
|
||||
<h2
|
||||
id="experiences-title"
|
||||
class="sr-only"
|
||||
>
|
||||
Experiences
|
||||
</h2>
|
||||
|
||||
<div class="grid gap-4 grid-cols-1">
|
||||
<UCard
|
||||
v-for="item in experiences"
|
||||
:key="item.id"
|
||||
variant="outline"
|
||||
color="neutral"
|
||||
>
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<div
|
||||
v-if="item.emoji"
|
||||
class="text-2xl leading-none"
|
||||
>
|
||||
{{ item.emoji }}
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<h3 class="text-lg md:text-xl font-semibold tracking-tight">
|
||||
{{ item.title }}<span
|
||||
v-if="item.type"
|
||||
class="text-md text-neutral-500 font-normal"
|
||||
> · {{ item.type }}</span>
|
||||
</h3>
|
||||
<p class="text-sm text-neutral-700 dark:text-neutral-300">
|
||||
<span class="font-medium mr-2">Company:</span>
|
||||
<span
|
||||
v-if="item.companyUrl"
|
||||
class="underline decoration-neutral-400/70 underline-offset-4 hover:decoration-neutral-600 dark:hover:decoration-neutral-300"
|
||||
>
|
||||
<NuxtLink
|
||||
:to="item.companyUrl"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>{{ item.company }}</NuxtLink>
|
||||
</span>
|
||||
<span v-else>{{ item.company }}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-sm text-neutral-700 dark:text-neutral-300 flex flex-wrap items-center gap-2">
|
||||
<span class="font-medium">Dates:</span>
|
||||
<span>{{ formatDate(item.startDate) }} — {{ formatDate(item.endDate) }}</span>
|
||||
<span
|
||||
v-if="item.duration"
|
||||
class="text-neutral-500"
|
||||
>({{ item.duration }})</span>
|
||||
</p>
|
||||
|
||||
<p class="text-sm text-neutral-700 dark:text-neutral-300 flex items-center gap-2">
|
||||
<span class="font-medium">Location:</span>
|
||||
<span>{{ item.location }}</span>
|
||||
</p>
|
||||
|
||||
<p class="text-sm text-neutral-700 dark:text-neutral-300">
|
||||
{{ item.description }}
|
||||
</p>
|
||||
|
||||
<div
|
||||
v-if="item.tags?.length"
|
||||
class="flex flex-wrap gap-2"
|
||||
>
|
||||
<UBadge
|
||||
v-for="tag in item.tags"
|
||||
:key="tag"
|
||||
size="sm"
|
||||
variant="soft"
|
||||
color="primary"
|
||||
>
|
||||
{{ tag }}
|
||||
</UBadge>
|
||||
</div>
|
||||
</div>
|
||||
</UCard>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -7,7 +7,7 @@
|
||||
alt="Avatar"
|
||||
class="hover:rotate-360 duration-500 transform-gpu rounded-full"
|
||||
size="xl"
|
||||
src="/favicon.webp"
|
||||
src="/arthur.webp"
|
||||
/>
|
||||
</UTooltip>
|
||||
</ClientOnly>
|
||||
|
||||
43
app/components/home/Skills.vue
Normal file
43
app/components/home/Skills.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<script lang="ts" setup>
|
||||
const { skills } = await useContent()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
v-if="skills"
|
||||
class="my-8 space-y-6"
|
||||
aria-labelledby="skills-title"
|
||||
>
|
||||
<h2
|
||||
id="skills-title"
|
||||
class="sr-only"
|
||||
>
|
||||
Skills
|
||||
</h2>
|
||||
|
||||
<div
|
||||
v-for="skill in skills.body"
|
||||
:key="skill.id"
|
||||
>
|
||||
<div class>
|
||||
<h3 class="text-xl md:text-2xl font-semibold tracking-tight mb-4">
|
||||
{{ skill.name }}
|
||||
</h3>
|
||||
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<UBadge
|
||||
v-for="item in skill.items"
|
||||
:key="item.name"
|
||||
:icon="item.icon"
|
||||
variant="soft"
|
||||
color="primary"
|
||||
class="transition-colors duration-200 hover:opacity-80"
|
||||
:aria-label="item.name"
|
||||
>
|
||||
{{ item.name }}
|
||||
</UBadge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
Reference in New Issue
Block a user