Skip to content

Commit d238052

Browse files
committed
add resumes and json
1 parent 44c3c5b commit d238052

File tree

4 files changed

+161
-241
lines changed

4 files changed

+161
-241
lines changed

app/pages/resume.vue

Lines changed: 75 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,13 @@
22
import type { Experience, TranslatedExperiences } from '~/types/experience'
33
import type { Education, TranslatedEducation } from '~/types/education'
44
5-
definePageMeta({
6-
layout: 'resume'
7-
})
5+
definePageMeta({ layout: 'resume' })
86
97
const { global } = useAppConfig()
10-
const { t } = useI18n()
8+
const { t, locale } = useI18n()
119
const img = useImage()
1210
const age = useAge()
13-
const locale = useI18n().locale.value
14-
1511
const isAvailable = global.available
16-
1712
const { experienceString } = useExperienceString()
1813
1914
const { data: experienceByLang } = await useAsyncData<TranslatedExperiences>('experiences', () =>
@@ -24,196 +19,114 @@ const { data: techs } = await useAsyncData('technologies', () =>
2419
$fetch('/api/technologies')
2520
)
2621
27-
const combinedTechs = computed(() => {
28-
const frontend = techs.value?.frontend || []
29-
const backend = techs.value?.backend || []
30-
return [...frontend, ...backend]
31-
})
32-
33-
const experiences = computed<Experience[]>(() => {
34-
if (!experienceByLang.value) return []
35-
if (locale in experienceByLang.value) {
36-
return experienceByLang.value[locale as keyof TranslatedExperiences]
37-
}
38-
return []
39-
})
40-
4122
const { data: educationByLang } = await useAsyncData<TranslatedEducation>('education', () =>
4223
$fetch('/api/education')
4324
)
4425
45-
const educations = computed<Education[]>(() => {
46-
if (!educationByLang.value) return []
47-
if (locale in educationByLang.value) {
48-
return educationByLang.value[locale as keyof TranslatedEducation]
49-
}
50-
return []
51-
})
26+
function getByLocale<T>(data: Record<string, T[]> | undefined): T[] {
27+
if (!data) return []
28+
return data[locale.value as keyof typeof data] || []
29+
}
30+
31+
const experiences = computed(() => getByLocale<Experience>(experienceByLang.value))
32+
const educations = computed(() => getByLocale<Education>(educationByLang.value))
33+
const combinedTechs = computed(() => [...(techs.value?.frontend || []), ...(techs.value?.backend || [])])
5234
</script>
5335

5436
<template>
5537
<main>
5638
<header class="flex justify-between gap-3">
5739
<div class="w-full bg-neutral-200 p-3 rounded-3xl">
58-
<div class="w-full">
59-
<div>
60-
<div class="flex items-start mb-5 gap-3">
61-
<div class="relative">
62-
<NuxtImg
63-
class="rounded-3xl pointer-events-none select-none min-w-[100px] min-h-[100px]"
64-
width="100"
65-
height="100"
66-
format="webp"
67-
:src="global.picture.src"
68-
:alt="global.picture.alt"
69-
:placeholder="img(global.picture.src, { h: 10, f: 'png', blur: 0.3, q: 50 })"
70-
/>
71-
<div class="absolute -bottom-2 -right-4">
72-
<div
73-
class="inline-flex items-center gap-2 text-sm font-medium transition-all"
74-
:class="isAvailable ? 'text-green-500' : 'text-red-500'"
75-
>
76-
<span
77-
class="relative flex h-4 w-4"
78-
:class="isAvailable ? 'text-green-500' : 'text-red-500'"
79-
>
80-
<span
81-
class="animate-ping absolute inline-flex h-full w-full rounded-full opacity-75"
82-
:class="isAvailable ? 'bg-green-400' : 'bg-red-400'"
83-
/>
84-
<span
85-
class="relative inline-flex rounded-full h-4 w-4"
40+
<div class="flex items-start mb-5 gap-3">
41+
<div class="relative">
42+
<NuxtImg
43+
class="rounded-3xl pointer-events-none select-none min-w-[100px] min-h-[100px]"
44+
width="100" height="100" format="webp"
45+
:src="global.picture.src" :alt="global.picture.alt"
46+
:placeholder="img(global.picture.src, { h: 10, f: 'png', blur: 0.3, q: 50 })"
47+
/>
48+
<div class="absolute -bottom-2 -right-4">
49+
<div class="inline-flex items-center gap-2 text-sm font-medium transition-all"
50+
:class="isAvailable ? 'text-green-500' : 'text-red-500'">
51+
<span class="relative flex h-4 w-4">
52+
<span class="animate-ping absolute inline-flex h-full w-full rounded-full opacity-75"
53+
:class="isAvailable ? 'bg-green-400' : 'bg-red-400'" />
54+
<span class="relative inline-flex rounded-full h-4 w-4"
8655
:class="isAvailable ? 'bg-green-500 shadow-green-500/60' : 'bg-red-500 shadow-red-500/60'"
87-
style="box-shadow: 0 0 8px currentColor;"
88-
/>
89-
</span>
90-
91-
<span />
92-
</div>
93-
</div>
94-
</div>
95-
<div class="w-full flex flex-col gap-1">
96-
<div class="flex items-center w-full justify-between">
97-
<h1 class="font-bold text-2xl">
98-
{{ t('resume.name') }} {{ t('resume.surname') }}
99-
</h1>
100-
<div class="border border-neutral-700 px-2 py-1 rounded-full text-nowrap text-xs">
101-
{{ experienceString }}
102-
</div>
103-
</div>
104-
<div>
105-
<h3 class="font-semibold text-xl">
106-
{{ t('resume.position') }}
107-
</h3>
108-
<h5 class="font-semibold text-neutral-700">
109-
({{ t('resume.stack') }})
110-
</h5>
111-
</div>
56+
style="box-shadow: 0 0 8px currentColor;" />
57+
</span>
11258
</div>
11359
</div>
11460
</div>
61+
62+
<div class="w-full flex flex-col gap-1">
63+
<div class="flex items-center w-full justify-between">
64+
<h1 class="font-bold text-2xl">{{ t('resume.name') }} {{ t('resume.surname') }}</h1>
65+
<div class="border border-neutral-700 px-2 py-1 rounded-full text-xs">{{ experienceString }}</div>
66+
</div>
67+
<div>
68+
<h3 class="font-semibold text-xl">{{ t('resume.position') }}</h3>
69+
<h5 class="font-semibold text-neutral-700">({{ t('resume.stack') }})</h5>
70+
</div>
71+
</div>
11572
</div>
116-
<div>
117-
<p class="text-neutral-700 text-sm line-clamp-3">
118-
{{ $t('about.intro', { age }) }}
119-
</p>
120-
</div>
73+
74+
<p class="text-neutral-700 text-sm line-clamp-4">{{ $t('about.intro', { age }) }}</p>
12175
</div>
76+
12277
<div class="w-1/3 bg-neutral-200 p-3 rounded-3xl flex flex-col justify-between">
12378
<div>
124-
<h5 class="font-semibold">
125-
{{ $t('resume.contacts') }}
126-
</h5>
127-
<div class="text-neutral-700">
128-
{{ global.phone }} <br>{{ global.email }} <br> {{ global.telegram }}
129-
</div>
79+
<h5 class="font-semibold">{{ $t('resume.contacts') }}</h5>
80+
<div class="text-neutral-700">{{ global.phone }}<br>{{ global.email }}<br>{{ global.telegram }}</div>
13081
</div>
13182
<div>
132-
<h5 class="font-semibold">
133-
{{ $t('resume.portfolio') }}
134-
</h5>
135-
<div class="text-neutral-700">
136-
vahe.anidzen.com
137-
</div>
83+
<h5 class="font-semibold">{{ $t('resume.portfolio') }}</h5>
84+
<div class="text-neutral-700">vahe.anidzen.com</div>
13885
</div>
13986
</div>
14087
</header>
14188

142-
<section class="mt-3 border border-neutral-700 rounded-3xl flex-1 px-3 py-6">
89+
<section class="mt-3 border border-neutral-700 rounded-3xl flex-1 px-3 py-5">
14390
<div class="flex gap-3">
144-
<div class="w-full flex">
145-
<div class="space-y-4">
146-
<div>
147-
<h4 class="font-semibold text-xl mb-1">
148-
{{ t('experience.title') }} — {{ experienceString }}
149-
</h4>
150-
<h6 class="text-neutral-700 text-sm">
151-
{{ t('experience.description') }}
152-
</h6>
153-
</div>
154-
<ul class="space-y-3">
155-
<li
156-
v-for="(exp, index) in experiences"
157-
:key="index"
158-
>
159-
<div class="text-sm text-neutral-700 flex flex-row justify-between mb-2 items-center gap-5">
160-
<span class="font-medium text-nowrap">
161-
{{ exp.company }}
162-
</span>
163-
<hr class="w-full border-neutral-200 hidden lg:block">
164-
<span class="text-nowrap">
165-
{{ exp.period }}
166-
</span>
167-
</div>
168-
<h3 class="font-semibold text-xl">
169-
{{ exp.title }}
170-
</h3>
171-
<p class="text-base text-neutral-700 text-sm line-clamp-2">
172-
{{ exp.description }}
173-
</p>
174-
</li>
175-
</ul>
91+
<div class="w-full flex flex-col space-y-4">
92+
<div>
93+
<h4 class="font-semibold text-xl mb-1">{{ t('experience.title') }} — {{ experienceString }}</h4>
94+
<h6 class="text-neutral-700 text-sm">{{ t('experience.description') }}</h6>
17695
</div>
96+
97+
<ul class="space-y-3">
98+
<li v-for="(exp, i) in experiences" :key="i">
99+
<div class="text-sm text-neutral-700 flex justify-between mb-2 items-center gap-5">
100+
<span class="font-medium text-nowrap">{{ exp.company }}</span>
101+
<hr class="w-full border-neutral-200 hidden lg:block">
102+
<span class="text-nowrap">{{ exp.period }}</span>
103+
</div>
104+
<h3 class="font-semibold text-xl">{{ exp.title }}</h3>
105+
<p class="text-base text-neutral-700 text-sm line-clamp-4">{{ exp.description }}</p>
106+
</li>
107+
</ul>
177108
</div>
109+
178110
<div class="w-1/3 flex flex-col">
179-
<h3 class="font-semibold text-xl mb-1">
180-
{{ $t('resume.skills') }}
181-
</h3>
111+
<h3 class="font-semibold text-xl mb-1">{{ $t('resume.skills') }}</h3>
182112
<div class="flex flex-wrap gap-1.5">
183-
<div
184-
v-for="tech in combinedTechs || []"
185-
:key="tech.name"
186-
class="border border-neutral-400 px-1 py-0.1 rounded-full text-nowrap text-xs"
187-
>
113+
<div v-for="tech in combinedTechs" :key="tech.name"
114+
class="border border-neutral-400 px-1 py-0.1 rounded-full text-xs">
188115
<span class="text-[10px] text-black">{{ tech.name }}</span>
189116
</div>
190117
</div>
191118
</div>
192119
</div>
193-
<div class="mt-4 border-t-1 border-neutral-200 pt-4 md:gap-5">
194-
<div class="space-y-4 border-r border-neutral-200">
195-
<div>
196-
<h4 class="font-semibold text-xl">
197-
{{ t('education.title') }}
198-
</h4>
199-
<h6 class="text-neutral-700 text-sm">
200-
{{ t('education.description') }}
201-
</h6>
202-
</div>
203-
<div
204-
v-for="(item, index) in educations"
205-
:key="'edu-' + index"
206-
class="border-l pl-4 border-neutral-200"
207-
>
208-
<h5 class="font-semibold text-base">
209-
{{ item.title }}
210-
</h5>
211-
<p class="text-sm text-neutral-700">
212-
{{ item.description }}
213-
</p>
214-
</div>
215-
</div>
216120

121+
<div class="mt-4 border-t border-neutral-200 pt-4 md:gap-5 space-y-4 border-neutral-200">
122+
<div>
123+
<h4 class="font-semibold text-xl">{{ t('education.title') }}</h4>
124+
<h6 class="text-neutral-700 text-sm">{{ t('education.description') }}</h6>
125+
</div>
126+
<div v-for="(edu, i) in educations" :key="i" class="border-l pl-4 border-neutral-200">
127+
<h5 class="font-semibold text-base">{{ edu.title }}</h5>
128+
<p class="text-sm text-neutral-700">{{ edu.description }}</p>
129+
</div>
217130
</div>
218131
</section>
219132
</main>

i18n/locales/en-US.json

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,60 +4,62 @@
44
"projects": "Projects",
55
"blog": "Blog",
66
"shop": "Shop",
7-
"anidzen": "Anidzen",
8-
"about": "About Me"
7+
"about": "About"
98
},
109
"openInGithub": "Open in Github",
1110
"cta": {
1211
"title": "Hi, I'm Vahe — Full Stack Developer",
13-
"description": "Developing scalable products with a strong focus on high performance, stability, and enhancing user experience for businesses.",
14-
"resumeEn": "Resume (EN)",
15-
"resumeHy": "Resume (HY)",
16-
"resumeRu": "Resume (RU)",
17-
"resumeUk": "Resume (UK)",
18-
"projects": "View Projects",
19-
"downloadPlaceholder": "Download Resume"
12+
"description": "I create reliable and scalable web solutions focusing on performance, stability, and user-friendliness. I help companies turn ideas into stable and effective products.",
13+
"resume": {
14+
"label": "Resume",
15+
"download": "Download Resume",
16+
"languages": {
17+
"en": "English",
18+
"hy": "Armenian",
19+
"ru": "Russian",
20+
"uk": "Ukrainian"
21+
}
22+
},
23+
"projects": "View Projects"
2024
},
2125
"availability": {
2226
"available": "Available for work",
23-
"unavailable": "Not available now"
27+
"unavailable": "Currently unavailable"
2428
},
2529
"experience": {
2630
"title": "Experience",
27-
"description": "My professional journey, key roles, and achievements in various companies.",
28-
"years": ["year", "years", "years"],
29-
"months": ["month", "months", "months"],
31+
"description": "My professional path, key roles, and achievements in companies I collaborated with.",
32+
"years": ["year", "years"],
33+
"months": ["month", "months"],
3034
"lessThanMonth": "less than a month"
3135
},
3236
"education": {
3337
"title": "Education",
3438
"description": "My education and internships"
3539
},
3640
"activity": {
37-
"title": "Extracurricular Activities",
38-
"description": "My projects and initiatives outside of my main work.",
39-
"opensource": "I participate in the development of the open-source ecosystem — from Nuxt UI to LibreTranslate and other projects.",
40-
"personal": "In my free time, I work on various initiatives and collaborative projects: OTA-KU, Currenzy, GeoFence, Hentai-Voice, and others."
41+
"title": "Extracurricular Activity",
42+
"description": "My projects and initiatives outside of work."
4143
},
4244
"achievements": {
43-
"title": "My Achievements",
44-
"description": "Below are key milestones in my professional journey."
45+
"title": "Achievements",
46+
"description": "Milestones of my professional journey."
4547
},
4648
"about": {
4749
"title": "About Me",
4850
"description": "About me as a developer",
49-
"intro": "My name is Vahe, I am {age} years old. I am a full-stack developer specializing in Nuxt.js and Laravel. I create fast and convenient web applications, have experience with microservices, APIs (REST and GraphQL), system integration, and complex UIs. I value reliability, clean code, and projects that deliver real impact."
51+
"intro": "My name is Vahe, I am {age} years old. Full-stack developer specializing in Nuxt.js and Laravel. I create fast and convenient web apps, worked with microservices, APIs (REST & GraphQL), system integrations, and complex UI. I value reliability, clean code, and projects that bring real value."
5052
},
5153
"projects": {
52-
"title": "What I Create and Develop",
53-
"description": "Author's projects and commercial cases brought to life from scratch — from idea to scaling. I implement solutions in IT, design, and related creative and business areas.",
54-
"have_idea": "Have a project in mind?",
55-
"what_i_offer": "I am happy to help bring your idea to life — from the initial concept to a fully finished solution. We can discuss every detail of the project, choose the most suitable technologies and approaches, ensuring the result is as efficient and high-quality as possible. My goal is to make the process transparent and convenient for you, so your idea is realized exactly as you envision it.",
56-
"contact_telegram": "Message on Telegram"
54+
"title": "What I Build and Develop",
55+
"description": "Author projects and commercial cases implemented from scratch — from idea to scaling. I implement IT, design, and other creative/business solutions.",
56+
"have_idea": "Got a project idea?",
57+
"what_i_offer": "I’ll be happy to help bring your idea to life — from initial concept to a fully ready solution. We can discuss all project details, choose the best technologies and approaches for maximum efficiency. My goal is to make the process transparent and convenient so your idea becomes exactly what you imagined.",
58+
"contact_telegram": "Contact on Telegram"
5759
},
5860
"shop": {
59-
"title": "Custom Solutions and Projects",
60-
"description": "I sell and share my own work — from sleek landing pages to scalable microservice systems and turnkey solutions. Everything you need to launch and grow your product.",
61+
"title": "Author Solutions and Projects",
62+
"description": "I sell and share my own developments — from stylish landing pages to large microservice systems and ready-to-use solutions. Everything needed for a fast start and product growth.",
6163
"discount": "Discount",
6264
"free": "Free",
6365
"watch": "View",

0 commit comments

Comments
 (0)