fix: update portfolio branding to "Killian' DAL-CIN" across all documentation and components
- Corrected the name in various files including CLAUDE.md, README.md, and configuration files to reflect the updated branding. - Ensured consistency in the use of the new name throughout the project, enhancing brand identity. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+47
-51
@@ -65,42 +65,45 @@ const approachCards = computed(() => [
|
||||
<template>
|
||||
<div>
|
||||
<!-- Hero Section -->
|
||||
<section class="pt-16 pb-20 px-4 bg-gray-50 dark:bg-gray-900/30">
|
||||
<div class="max-w-4xl mx-auto text-center">
|
||||
<span class="text-sm font-semibold text-brand-500 dark:text-brand-400 uppercase tracking-wider">About</span>
|
||||
<h1 class="text-4xl sm:text-5xl font-bold mt-2 mb-6 text-gray-900 dark:text-white">
|
||||
<section class="relative pt-20 pb-20 px-4 sm:px-6 lg:px-8 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gray-50/80 dark:bg-gray-900/40" aria-hidden="true" />
|
||||
<div class="absolute top-0 right-0 w-[600px] h-[600px] bg-brand-500/5 dark:bg-brand-500/8 rounded-full blur-3xl -translate-y-1/2 translate-x-1/4 pointer-events-none" aria-hidden="true" />
|
||||
|
||||
<div class="relative z-10 max-w-4xl mx-auto text-center">
|
||||
<span class="font-mono text-sm text-brand-500 dark:text-brand-400 tracking-wider">// about</span>
|
||||
<h1 class="text-4xl sm:text-5xl lg:text-6xl font-bold mt-3 mb-6 bg-gradient-to-r from-gray-900 via-gray-800 to-gray-600 dark:from-white dark:via-gray-200 dark:to-gray-500 bg-clip-text text-transparent">
|
||||
{{ t('about.title') }}
|
||||
</h1>
|
||||
<p class="text-xl text-gray-500 dark:text-gray-400 mb-10 max-w-2xl mx-auto">
|
||||
<p class="text-xl text-gray-500 dark:text-gray-400 mb-12 max-w-2xl mx-auto leading-relaxed">
|
||||
{{ t('about.subtitle') }}
|
||||
</p>
|
||||
<div class="space-y-4 text-lg text-gray-600 dark:text-gray-400 max-w-3xl mx-auto leading-relaxed">
|
||||
<p>{{ t('about.intro.content') }}</p>
|
||||
<p>{{ t('about.experience.content') }}</p>
|
||||
<div class="max-w-3xl mx-auto space-y-6">
|
||||
<p class="text-lg text-gray-600 dark:text-gray-400 leading-relaxed rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/60 dark:bg-gray-900/40 backdrop-blur-sm p-6 sm:p-8 text-left">{{ t('about.intro.content') }}</p>
|
||||
<p class="text-lg text-gray-600 dark:text-gray-400 leading-relaxed rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/60 dark:bg-gray-900/40 backdrop-blur-sm p-6 sm:p-8 text-left">{{ t('about.experience.content') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Skills Section -->
|
||||
<section class="py-20 md:py-28 px-4">
|
||||
<section class="py-24 md:py-32 px-4 sm:px-6 lg:px-8">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<div class="text-center mb-14">
|
||||
<span class="text-sm font-semibold text-brand-500 dark:text-brand-400 uppercase tracking-wider">Tech Stack</span>
|
||||
<h2 class="text-3xl sm:text-4xl font-bold mt-2 text-gray-900 dark:text-white">{{ t('about.skills.title') }}</h2>
|
||||
<p class="text-lg text-gray-500 dark:text-gray-400 mt-3 max-w-2xl mx-auto">
|
||||
<div class="text-center mb-16">
|
||||
<span class="font-mono text-sm text-brand-500 dark:text-brand-400 tracking-wider">// tech-stack</span>
|
||||
<h2 class="text-3xl sm:text-4xl lg:text-5xl font-bold mt-3 bg-gradient-to-r from-gray-900 via-gray-800 to-gray-600 dark:from-white dark:via-gray-200 dark:to-gray-500 bg-clip-text text-transparent">{{ t('about.skills.title') }}</h2>
|
||||
<p class="text-lg text-gray-500 dark:text-gray-400 mt-4 max-w-2xl mx-auto leading-relaxed">
|
||||
{{ t('about.subtitle') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Tech Categories Grid -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
||||
<!-- Tech Categories Bento Grid -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-5 mb-5">
|
||||
<div
|
||||
v-for="category in techCategories"
|
||||
:key="category.key"
|
||||
class="rounded-2xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 p-6 sm:p-8"
|
||||
class="group rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/80 dark:bg-gray-900/60 backdrop-blur-sm p-7 sm:p-8 transition-all duration-300 hover:border-brand-500/30 hover:shadow-lg hover:shadow-brand-500/5"
|
||||
>
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div class="w-10 h-10 rounded-xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center">
|
||||
<div class="w-10 h-10 rounded-xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center transition-all duration-300 group-hover:bg-brand-500/20 group-hover:scale-110">
|
||||
<UIcon :name="category.icon" class="text-xl text-brand-600 dark:text-brand-400" />
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white">{{ category.title }}</h3>
|
||||
@@ -117,9 +120,9 @@ const approachCards = computed(() => [
|
||||
</div>
|
||||
|
||||
<!-- Operating Systems -->
|
||||
<div class="rounded-2xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 p-6 sm:p-8">
|
||||
<div class="group rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/80 dark:bg-gray-900/60 backdrop-blur-sm p-7 sm:p-8 transition-all duration-300 hover:border-brand-500/30 hover:shadow-lg hover:shadow-brand-500/5">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div class="w-10 h-10 rounded-xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center">
|
||||
<div class="w-10 h-10 rounded-xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center transition-all duration-300 group-hover:bg-brand-500/20 group-hover:scale-110">
|
||||
<UIcon name="i-lucide-monitor" class="text-xl text-brand-600 dark:text-brand-400" />
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white">{{ t('about.skills.systems') }}</h3>
|
||||
@@ -137,28 +140,34 @@ const approachCards = computed(() => [
|
||||
</section>
|
||||
|
||||
<!-- Approach Section -->
|
||||
<section class="py-20 md:py-28 px-4 bg-gray-50 dark:bg-gray-900/30">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<div class="text-center mb-14">
|
||||
<span class="text-sm font-semibold text-brand-500 dark:text-brand-400 uppercase tracking-wider">Methodology</span>
|
||||
<h2 class="text-3xl sm:text-4xl font-bold mt-2 text-gray-900 dark:text-white">{{ t('about.approach.title') }}</h2>
|
||||
<p class="text-lg text-gray-500 dark:text-gray-400 mt-3 max-w-2xl mx-auto">
|
||||
<section class="relative py-24 md:py-32 px-4 sm:px-6 lg:px-8 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gray-50/80 dark:bg-gray-900/40" aria-hidden="true" />
|
||||
<div class="absolute bottom-0 left-0 w-[500px] h-[500px] bg-brand-500/5 dark:bg-brand-500/8 rounded-full blur-3xl translate-y-1/2 -translate-x-1/4 pointer-events-none" aria-hidden="true" />
|
||||
|
||||
<div class="relative z-10 max-w-7xl mx-auto">
|
||||
<div class="text-center mb-16">
|
||||
<span class="font-mono text-sm text-brand-500 dark:text-brand-400 tracking-wider">// methodology</span>
|
||||
<h2 class="text-3xl sm:text-4xl lg:text-5xl font-bold mt-3 bg-gradient-to-r from-gray-900 via-gray-800 to-gray-600 dark:from-white dark:via-gray-200 dark:to-gray-500 bg-clip-text text-transparent">{{ t('about.approach.title') }}</h2>
|
||||
<p class="text-lg text-gray-500 dark:text-gray-400 mt-4 max-w-2xl mx-auto leading-relaxed">
|
||||
{{ t('about.approach.subtitle') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||
<div
|
||||
v-for="(card, index) in approachCards"
|
||||
:key="index"
|
||||
class="group rounded-2xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 p-6 sm:p-8 transition-all duration-300 hover:border-brand-500/30 hover:shadow-lg hover:shadow-brand-500/5"
|
||||
class="group rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/80 dark:bg-gray-900/60 backdrop-blur-sm p-7 sm:p-8 transition-all duration-300 hover:border-brand-500/40 hover:shadow-xl hover:shadow-brand-500/10 hover:-translate-y-1"
|
||||
>
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="w-12 h-12 rounded-xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center shrink-0 transition-colors group-hover:bg-brand-500/20">
|
||||
<!-- Hover glow -->
|
||||
<div class="absolute inset-0 rounded-2xl bg-gradient-to-br from-brand-500/0 to-emerald-500/0 group-hover:from-brand-500/5 group-hover:to-emerald-500/5 transition-all duration-500 pointer-events-none" aria-hidden="true" />
|
||||
|
||||
<div class="relative z-10 flex items-start gap-4">
|
||||
<div class="w-12 h-12 rounded-xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center shrink-0 transition-all duration-300 group-hover:bg-brand-500/20 group-hover:scale-110">
|
||||
<UIcon :name="card.icon" class="text-xl text-brand-600 dark:text-brand-400" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-2">{{ card.title }}</h3>
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-2 group-hover:text-brand-600 dark:group-hover:text-brand-400 transition-colors">{{ card.title }}</h3>
|
||||
<p class="text-gray-500 dark:text-gray-400 leading-relaxed">{{ card.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -168,26 +177,13 @@ const approachCards = computed(() => [
|
||||
</section>
|
||||
|
||||
<!-- CTA Section -->
|
||||
<section class="py-20 md:py-28 px-4">
|
||||
<div class="max-w-5xl mx-auto">
|
||||
<div class="relative overflow-hidden rounded-3xl bg-gradient-to-br from-brand-600 via-brand-500 to-emerald-500 px-8 py-16 sm:px-16 sm:py-20 text-center">
|
||||
<div class="absolute top-0 left-0 w-72 h-72 bg-white/10 rounded-full -translate-x-1/2 -translate-y-1/2 blur-2xl" aria-hidden="true" />
|
||||
<div class="absolute bottom-0 right-0 w-96 h-96 bg-black/10 rounded-full translate-x-1/3 translate-y-1/3 blur-2xl" aria-hidden="true" />
|
||||
|
||||
<div class="relative z-10">
|
||||
<h2 class="text-3xl sm:text-4xl font-bold text-white mb-4">{{ t('about.cta.title') }}</h2>
|
||||
<p class="text-lg text-white/80 mb-10 max-w-2xl mx-auto">{{ t('about.cta.description') }}</p>
|
||||
<div class="flex flex-wrap justify-center gap-4">
|
||||
<UButton :to="localePath('/contact')" size="xl" color="white" class="font-semibold">
|
||||
{{ t('about.cta.button') }}
|
||||
</UButton>
|
||||
<UButton :to="localePath('/projects')" size="xl" variant="outline" color="white" class="font-semibold">
|
||||
{{ t('home.cta.viewProjects') }}
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<CTASection
|
||||
:title="t('about.cta.title')"
|
||||
:subtitle="t('about.cta.description')"
|
||||
:primary-text="t('about.cta.button')"
|
||||
primary-to="/contact"
|
||||
:secondary-text="t('home.cta.viewProjects')"
|
||||
secondary-to="/projects"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
+62
-57
@@ -18,43 +18,49 @@ useSeoMeta({
|
||||
<template>
|
||||
<div>
|
||||
<!-- Hero Section -->
|
||||
<section class="pt-16 pb-12 px-4 bg-gray-50 dark:bg-gray-900/30">
|
||||
<div class="max-w-4xl mx-auto text-center">
|
||||
<span class="text-sm font-semibold text-brand-500 dark:text-brand-400 uppercase tracking-wider">Contact</span>
|
||||
<h1 class="text-4xl sm:text-5xl font-bold mt-2 mb-6 text-gray-900 dark:text-white">
|
||||
<section class="relative pt-20 pb-16 px-4 sm:px-6 lg:px-8 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gray-50/80 dark:bg-gray-900/40" aria-hidden="true" />
|
||||
<div class="absolute top-0 left-1/2 -translate-x-1/2 w-[800px] h-[400px] bg-brand-500/5 dark:bg-brand-500/8 rounded-full blur-3xl pointer-events-none" aria-hidden="true" />
|
||||
|
||||
<div class="relative z-10 max-w-4xl mx-auto text-center">
|
||||
<span class="font-mono text-sm text-brand-500 dark:text-brand-400 tracking-wider">// contact</span>
|
||||
<h1 class="text-4xl sm:text-5xl lg:text-6xl font-bold mt-3 mb-6 bg-gradient-to-r from-gray-900 via-gray-800 to-gray-600 dark:from-white dark:via-gray-200 dark:to-gray-500 bg-clip-text text-transparent">
|
||||
{{ t('contact.title') }}
|
||||
</h1>
|
||||
<p class="text-xl text-gray-500 dark:text-gray-400 mb-10 max-w-2xl mx-auto">
|
||||
<p class="text-xl text-gray-500 dark:text-gray-400 mb-12 max-w-2xl mx-auto leading-relaxed">
|
||||
{{ t('contact.subtitle') }}
|
||||
</p>
|
||||
|
||||
<!-- Stats -->
|
||||
<div class="flex flex-wrap justify-center gap-10">
|
||||
<div class="flex flex-wrap justify-center gap-8 sm:gap-12">
|
||||
<div class="text-center">
|
||||
<div class="text-3xl font-extrabold text-brand-500 dark:text-brand-400">24-48h</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400 mt-1">{{ t('contact.stats.responseTime') }}</div>
|
||||
<div class="text-3xl sm:text-4xl font-black bg-gradient-to-b from-brand-400 to-brand-600 bg-clip-text text-transparent">24-48h</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400 mt-2 font-medium">{{ t('contact.stats.responseTime') }}</div>
|
||||
</div>
|
||||
<div class="w-px bg-gray-200 dark:bg-gray-800 hidden sm:block" />
|
||||
<div class="w-px bg-gradient-to-b from-transparent via-gray-300 dark:via-gray-700 to-transparent hidden sm:block" />
|
||||
<div class="text-center">
|
||||
<div class="text-3xl font-extrabold text-brand-500 dark:text-brand-400">100%</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400 mt-1">{{ t('contact.stats.satisfaction') }}</div>
|
||||
<div class="text-3xl sm:text-4xl font-black bg-gradient-to-b from-brand-400 to-brand-600 bg-clip-text text-transparent">100%</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400 mt-2 font-medium">{{ t('contact.stats.satisfaction') }}</div>
|
||||
</div>
|
||||
<div class="w-px bg-gray-200 dark:bg-gray-800 hidden sm:block" />
|
||||
<div class="w-px bg-gradient-to-b from-transparent via-gray-300 dark:via-gray-700 to-transparent hidden sm:block" />
|
||||
<div class="text-center">
|
||||
<div class="text-3xl font-extrabold text-brand-500 dark:text-brand-400">Remote</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400 mt-1">{{ t('contact.stats.collaboration') }}</div>
|
||||
<div class="text-3xl sm:text-4xl font-black bg-gradient-to-b from-brand-400 to-brand-600 bg-clip-text text-transparent">Remote</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400 mt-2 font-medium">{{ t('contact.stats.collaboration') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Two Column Layout -->
|
||||
<section class="py-16 md:py-20 px-4">
|
||||
<div class="max-w-6xl mx-auto grid grid-cols-1 lg:grid-cols-5 gap-10 lg:gap-16">
|
||||
<section class="py-16 md:py-24 px-4 sm:px-6 lg:px-8">
|
||||
<div class="max-w-6xl mx-auto grid grid-cols-1 lg:grid-cols-5 gap-8 lg:gap-12">
|
||||
<!-- Left: Contact Form (wider) -->
|
||||
<div class="lg:col-span-3">
|
||||
<div class="rounded-2xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 p-6 sm:p-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-6">{{ t('contact.form.title') }}</h2>
|
||||
<div class="rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/80 dark:bg-gray-900/60 backdrop-blur-sm p-7 sm:p-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-6 flex items-center gap-3">
|
||||
<div class="w-1 h-6 rounded-full bg-brand-500" />
|
||||
{{ t('contact.form.title') }}
|
||||
</h2>
|
||||
<ContactForm />
|
||||
</div>
|
||||
</div>
|
||||
@@ -62,53 +68,50 @@ useSeoMeta({
|
||||
<!-- Right: Contact Info + Social -->
|
||||
<div class="lg:col-span-2 flex flex-col gap-6">
|
||||
<!-- Contact Info -->
|
||||
<div class="rounded-2xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 p-6 sm:p-8">
|
||||
<h2 class="text-xl font-bold text-gray-900 dark:text-white mb-6">{{ t('contact.quickContact') }}</h2>
|
||||
<div class="flex flex-col gap-5">
|
||||
<div class="rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/80 dark:bg-gray-900/60 backdrop-blur-sm p-7 sm:p-8">
|
||||
<h2 class="text-xl font-bold text-gray-900 dark:text-white mb-6 flex items-center gap-3">
|
||||
<div class="w-1 h-5 rounded-full bg-brand-500" />
|
||||
{{ t('contact.quickContact') }}
|
||||
</h2>
|
||||
<div class="flex flex-col gap-4">
|
||||
<a
|
||||
:href="`mailto:${siteConfig.contact.email}`"
|
||||
class="flex items-center gap-4 group"
|
||||
class="flex items-center gap-4 p-3 rounded-xl border border-transparent hover:border-brand-500/20 hover:bg-brand-500/5 transition-all duration-200 group"
|
||||
>
|
||||
<div class="w-10 h-10 rounded-xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center shrink-0 transition-colors group-hover:bg-brand-500/20">
|
||||
<div class="w-10 h-10 rounded-xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center shrink-0 transition-all duration-300 group-hover:bg-brand-500/20 group-hover:scale-110">
|
||||
<UIcon name="i-lucide-mail" class="text-brand-600 dark:text-brand-400" />
|
||||
</div>
|
||||
<span class="text-gray-600 dark:text-gray-300 group-hover:text-brand-500 transition-colors">{{ siteConfig.contact.email }}</span>
|
||||
<span class="text-gray-600 dark:text-gray-300 group-hover:text-brand-500 transition-colors font-medium">{{ siteConfig.contact.email }}</span>
|
||||
</a>
|
||||
<a
|
||||
:href="`tel:${siteConfig.contact.phone.replace(/\s/g, '')}`"
|
||||
class="flex items-center gap-4 group"
|
||||
>
|
||||
<div class="w-10 h-10 rounded-xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center shrink-0 transition-colors group-hover:bg-brand-500/20">
|
||||
<UIcon name="i-lucide-phone" class="text-brand-600 dark:text-brand-400" />
|
||||
</div>
|
||||
<span class="text-gray-600 dark:text-gray-300 group-hover:text-brand-500 transition-colors">{{ siteConfig.contact.phone }}</span>
|
||||
</a>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex items-center gap-4 p-3">
|
||||
<div class="w-10 h-10 rounded-xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center shrink-0">
|
||||
<UIcon name="i-lucide-map-pin" class="text-brand-600 dark:text-brand-400" />
|
||||
</div>
|
||||
<span class="text-gray-600 dark:text-gray-300">{{ siteConfig.contact.location }}</span>
|
||||
<span class="text-gray-600 dark:text-gray-300 font-medium">{{ siteConfig.contact.location }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Social Links -->
|
||||
<div class="rounded-2xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 p-6 sm:p-8">
|
||||
<h2 class="text-xl font-bold text-gray-900 dark:text-white mb-6">{{ t('contact.findMeOn') }}</h2>
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/80 dark:bg-gray-900/60 backdrop-blur-sm p-7 sm:p-8">
|
||||
<h2 class="text-xl font-bold text-gray-900 dark:text-white mb-6 flex items-center gap-3">
|
||||
<div class="w-1 h-5 rounded-full bg-brand-500" />
|
||||
{{ t('contact.findMeOn') }}
|
||||
</h2>
|
||||
<div class="flex flex-col gap-2">
|
||||
<a
|
||||
v-for="social in siteConfig.social.filter(s => s.icon !== 'i-lucide-mail')"
|
||||
:key="social.name"
|
||||
:href="social.url"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="flex items-center gap-4 p-3 rounded-xl hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors group"
|
||||
class="flex items-center gap-4 p-3 rounded-xl border border-transparent hover:border-brand-500/20 hover:bg-brand-500/5 transition-all duration-200 group"
|
||||
>
|
||||
<div class="w-10 h-10 rounded-xl bg-gray-100 dark:bg-gray-800 flex items-center justify-center shrink-0 group-hover:bg-brand-500/10 transition-colors">
|
||||
<div class="w-10 h-10 rounded-xl bg-gray-100 dark:bg-gray-800/80 border border-gray-200/50 dark:border-gray-700/30 flex items-center justify-center shrink-0 group-hover:bg-brand-500/10 group-hover:border-brand-500/20 transition-all duration-300">
|
||||
<UIcon :name="social.icon" class="text-gray-500 dark:text-gray-400 group-hover:text-brand-500 transition-colors" />
|
||||
</div>
|
||||
<span class="text-gray-700 dark:text-gray-300 font-medium group-hover:text-brand-500 transition-colors">{{ social.name }}</span>
|
||||
<UIcon name="i-lucide-external-link" class="text-xs text-gray-400 dark:text-gray-600 ml-auto" />
|
||||
<UIcon name="i-lucide-external-link" class="text-xs text-gray-400 dark:text-gray-600 ml-auto group-hover:text-brand-400 transition-colors" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -117,38 +120,40 @@ useSeoMeta({
|
||||
</section>
|
||||
|
||||
<!-- FAQ Info Cards -->
|
||||
<section class="py-16 md:py-20 px-4 bg-gray-50 dark:bg-gray-900/30">
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<div class="text-center mb-14">
|
||||
<span class="text-sm font-semibold text-brand-500 dark:text-brand-400 uppercase tracking-wider">Info</span>
|
||||
<h2 class="text-3xl sm:text-4xl font-bold mt-2 text-gray-900 dark:text-white">{{ t('contact.faq.title') }}</h2>
|
||||
<p class="text-lg text-gray-500 dark:text-gray-400 mt-3 max-w-2xl mx-auto">
|
||||
<section class="relative py-20 md:py-28 px-4 sm:px-6 lg:px-8 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gray-50/80 dark:bg-gray-900/40" aria-hidden="true" />
|
||||
|
||||
<div class="relative z-10 max-w-6xl mx-auto">
|
||||
<div class="text-center mb-16">
|
||||
<span class="font-mono text-sm text-brand-500 dark:text-brand-400 tracking-wider">// info</span>
|
||||
<h2 class="text-3xl sm:text-4xl lg:text-5xl font-bold mt-3 bg-gradient-to-r from-gray-900 via-gray-800 to-gray-600 dark:from-white dark:via-gray-200 dark:to-gray-500 bg-clip-text text-transparent">{{ t('contact.faq.title') }}</h2>
|
||||
<p class="text-lg text-gray-500 dark:text-gray-400 mt-4 max-w-2xl mx-auto leading-relaxed">
|
||||
{{ t('contact.faq.subtitle') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div class="rounded-2xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 p-8 text-center group hover:border-brand-500/30 transition-all duration-300">
|
||||
<div class="w-14 h-14 rounded-2xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center mx-auto mb-5 group-hover:bg-brand-500/20 transition-colors">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-5">
|
||||
<div class="group rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/80 dark:bg-gray-900/60 backdrop-blur-sm p-8 text-center transition-all duration-300 hover:border-brand-500/40 hover:shadow-xl hover:shadow-brand-500/10 hover:-translate-y-1">
|
||||
<div class="w-14 h-14 rounded-2xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center mx-auto mb-5 transition-all duration-300 group-hover:bg-brand-500/20 group-hover:scale-110">
|
||||
<UIcon name="i-lucide-clock" class="text-2xl text-brand-600 dark:text-brand-400" />
|
||||
</div>
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-2">{{ t('contact.faq.responseTime.title') }}</h3>
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-3 group-hover:text-brand-600 dark:group-hover:text-brand-400 transition-colors">{{ t('contact.faq.responseTime.title') }}</h3>
|
||||
<p class="text-gray-500 dark:text-gray-400 text-sm leading-relaxed">{{ t('contact.faq.responseTime.description') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-2xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 p-8 text-center group hover:border-brand-500/30 transition-all duration-300">
|
||||
<div class="w-14 h-14 rounded-2xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center mx-auto mb-5 group-hover:bg-brand-500/20 transition-colors">
|
||||
<div class="group rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/80 dark:bg-gray-900/60 backdrop-blur-sm p-8 text-center transition-all duration-300 hover:border-brand-500/40 hover:shadow-xl hover:shadow-brand-500/10 hover:-translate-y-1">
|
||||
<div class="w-14 h-14 rounded-2xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center mx-auto mb-5 transition-all duration-300 group-hover:bg-brand-500/20 group-hover:scale-110">
|
||||
<UIcon name="i-lucide-building" class="text-2xl text-brand-600 dark:text-brand-400" />
|
||||
</div>
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-2">{{ t('contact.faq.projectTypes.title') }}</h3>
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-3 group-hover:text-brand-600 dark:group-hover:text-brand-400 transition-colors">{{ t('contact.faq.projectTypes.title') }}</h3>
|
||||
<p class="text-gray-500 dark:text-gray-400 text-sm leading-relaxed">{{ t('contact.faq.projectTypes.description') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-2xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 p-8 text-center group hover:border-brand-500/30 transition-all duration-300">
|
||||
<div class="w-14 h-14 rounded-2xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center mx-auto mb-5 group-hover:bg-brand-500/20 transition-colors">
|
||||
<div class="group rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/80 dark:bg-gray-900/60 backdrop-blur-sm p-8 text-center transition-all duration-300 hover:border-brand-500/40 hover:shadow-xl hover:shadow-brand-500/10 hover:-translate-y-1">
|
||||
<div class="w-14 h-14 rounded-2xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center mx-auto mb-5 transition-all duration-300 group-hover:bg-brand-500/20 group-hover:scale-110">
|
||||
<UIcon name="i-lucide-users" class="text-2xl text-brand-600 dark:text-brand-400" />
|
||||
</div>
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-2">{{ t('contact.faq.collaboration.title') }}</h3>
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-3 group-hover:text-brand-600 dark:group-hover:text-brand-400 transition-colors">{{ t('contact.faq.collaboration.title') }}</h3>
|
||||
<p class="text-gray-500 dark:text-gray-400 text-sm leading-relaxed">{{ t('contact.faq.collaboration.description') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+35
-47
@@ -33,21 +33,24 @@ const heroStats = computed(() => [
|
||||
<template>
|
||||
<div>
|
||||
<!-- Hero Section -->
|
||||
<section class="pt-16 pb-16 px-4 bg-gray-50 dark:bg-gray-900/30">
|
||||
<div class="max-w-4xl mx-auto text-center">
|
||||
<span class="text-sm font-semibold text-brand-500 dark:text-brand-400 uppercase tracking-wider">Fiverr</span>
|
||||
<h1 class="text-4xl sm:text-5xl font-bold mt-2 mb-6 text-gray-900 dark:text-white">
|
||||
<section class="relative pt-20 pb-16 px-4 sm:px-6 lg:px-8 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gray-50/80 dark:bg-gray-900/40" aria-hidden="true" />
|
||||
<div class="absolute top-0 right-0 w-[600px] h-[600px] bg-brand-500/5 dark:bg-brand-500/8 rounded-full blur-3xl -translate-y-1/2 translate-x-1/4 pointer-events-none" aria-hidden="true" />
|
||||
|
||||
<div class="relative z-10 max-w-4xl mx-auto text-center">
|
||||
<span class="font-mono text-sm text-brand-500 dark:text-brand-400 tracking-wider">// fiverr</span>
|
||||
<h1 class="text-4xl sm:text-5xl lg:text-6xl font-bold mt-3 mb-6 bg-gradient-to-r from-gray-900 via-gray-800 to-gray-600 dark:from-white dark:via-gray-200 dark:to-gray-500 bg-clip-text text-transparent">
|
||||
{{ t('fiverr.title') }}
|
||||
</h1>
|
||||
<p class="text-xl text-gray-500 dark:text-gray-400 mb-10 max-w-2xl mx-auto">
|
||||
<p class="text-xl text-gray-500 dark:text-gray-400 mb-12 max-w-2xl mx-auto leading-relaxed">
|
||||
{{ t('fiverr.subtitle') }}
|
||||
</p>
|
||||
|
||||
<!-- Stats -->
|
||||
<div class="flex flex-wrap justify-center gap-10 mb-10">
|
||||
<div class="flex flex-wrap justify-center gap-8 sm:gap-12 mb-12">
|
||||
<div v-for="stat in heroStats" :key="stat.label" class="text-center">
|
||||
<div class="text-4xl font-extrabold text-brand-500 dark:text-brand-400">{{ stat.number }}</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400 mt-1">{{ stat.label }}</div>
|
||||
<div class="text-4xl sm:text-5xl font-black bg-gradient-to-b from-brand-400 to-brand-600 bg-clip-text text-transparent">{{ stat.number }}</div>
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400 mt-2 font-medium">{{ stat.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -65,19 +68,19 @@ const heroStats = computed(() => [
|
||||
</section>
|
||||
|
||||
<!-- Services Section -->
|
||||
<section class="py-20 md:py-28 px-4">
|
||||
<section class="py-24 md:py-32 px-4 sm:px-6 lg:px-8">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<div class="text-center mb-14">
|
||||
<span class="text-sm font-semibold text-brand-500 dark:text-brand-400 uppercase tracking-wider">Services</span>
|
||||
<h2 class="text-3xl sm:text-4xl font-bold mt-2 text-gray-900 dark:text-white">{{ t('fiverr.services.title') }}</h2>
|
||||
<p class="text-lg text-gray-500 dark:text-gray-400 mt-3">{{ t('fiverr.services.subtitle') }}</p>
|
||||
<div class="text-center mb-16">
|
||||
<span class="font-mono text-sm text-brand-500 dark:text-brand-400 tracking-wider">// services</span>
|
||||
<h2 class="text-3xl sm:text-4xl lg:text-5xl font-bold mt-3 bg-gradient-to-r from-gray-900 via-gray-800 to-gray-600 dark:from-white dark:via-gray-200 dark:to-gray-500 bg-clip-text text-transparent">{{ t('fiverr.services.title') }}</h2>
|
||||
<p class="text-lg text-gray-500 dark:text-gray-400 mt-4 leading-relaxed">{{ t('fiverr.services.subtitle') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 lg:gap-8">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-5 lg:gap-6">
|
||||
<div
|
||||
v-for="service in services"
|
||||
:key="service.id"
|
||||
class="group rounded-2xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 overflow-hidden transition-all duration-300 hover:border-brand-500/30 hover:shadow-xl hover:shadow-brand-500/5 hover:-translate-y-1"
|
||||
class="group rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/80 dark:bg-gray-900/60 backdrop-blur-sm overflow-hidden transition-all duration-300 hover:border-brand-500/40 hover:shadow-xl hover:shadow-brand-500/10 hover:-translate-y-1.5"
|
||||
>
|
||||
<!-- Service Image -->
|
||||
<div class="relative overflow-hidden">
|
||||
@@ -87,10 +90,10 @@ const heroStats = computed(() => [
|
||||
class="w-full h-52 object-cover transition-transform duration-500 group-hover:scale-105"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black/40 via-transparent to-transparent" />
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-black/60 via-black/20 to-transparent" />
|
||||
<!-- Price badge overlay -->
|
||||
<div class="absolute bottom-3 left-3">
|
||||
<span class="px-3 py-1.5 rounded-lg bg-brand-500 text-white text-sm font-bold shadow-lg">
|
||||
<span class="px-3 py-1.5 rounded-lg bg-brand-500 text-white text-sm font-bold shadow-lg backdrop-blur-sm">
|
||||
{{ t('fiverr.pricing.startingAt') }} {{ service.price }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -98,8 +101,8 @@ const heroStats = computed(() => [
|
||||
<div class="absolute top-3 right-3">
|
||||
<span
|
||||
:class="service.url !== '#'
|
||||
? 'bg-green-500/90 text-white'
|
||||
: 'bg-yellow-500/90 text-white'"
|
||||
? 'bg-green-500/90 text-white backdrop-blur-sm'
|
||||
: 'bg-yellow-500/90 text-white backdrop-blur-sm'"
|
||||
class="px-2.5 py-1 rounded-lg text-xs font-semibold shadow-lg"
|
||||
>
|
||||
{{ service.url !== '#' ? t('fiverr.services.available') : t('fiverr.services.comingSoon') }}
|
||||
@@ -108,11 +111,11 @@ const heroStats = computed(() => [
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="p-6">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-2 group-hover:text-brand-500 transition-colors">
|
||||
<div class="p-6 sm:p-7">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-3 group-hover:text-brand-600 dark:group-hover:text-brand-400 transition-colors">
|
||||
{{ t(`fiverr.serviceData.${service.id}.title`) }}
|
||||
</h3>
|
||||
<p class="text-gray-500 dark:text-gray-400 mb-5 leading-relaxed">
|
||||
<p class="text-gray-500 dark:text-gray-400 mb-6 leading-relaxed">
|
||||
{{ t(`fiverr.serviceData.${service.id}.description`) }}
|
||||
</p>
|
||||
|
||||
@@ -142,7 +145,7 @@ const heroStats = computed(() => [
|
||||
</section>
|
||||
|
||||
<!-- FAQ Section -->
|
||||
<div class="bg-gray-50 dark:bg-gray-900/30">
|
||||
<div class="relative bg-gray-50/50 dark:bg-gray-900/20">
|
||||
<FAQSection
|
||||
:faqs="homeFAQs"
|
||||
:title="t('fiverr.faq.title')"
|
||||
@@ -151,29 +154,14 @@ const heroStats = computed(() => [
|
||||
</div>
|
||||
|
||||
<!-- CTA Section -->
|
||||
<section class="py-20 md:py-28 px-4">
|
||||
<div class="max-w-5xl mx-auto">
|
||||
<div class="relative overflow-hidden rounded-3xl bg-gradient-to-br from-brand-600 via-brand-500 to-emerald-500 px-8 py-16 sm:px-16 sm:py-20 text-center">
|
||||
<div class="absolute top-0 left-0 w-72 h-72 bg-white/10 rounded-full -translate-x-1/2 -translate-y-1/2 blur-2xl" aria-hidden="true" />
|
||||
<div class="absolute bottom-0 right-0 w-96 h-96 bg-black/10 rounded-full translate-x-1/3 translate-y-1/3 blur-2xl" aria-hidden="true" />
|
||||
|
||||
<div class="relative z-10">
|
||||
<h2 class="text-3xl sm:text-4xl font-bold text-white mb-4">{{ t('fiverr.cta.title') }}</h2>
|
||||
<p class="text-lg text-white/80 mb-10 max-w-2xl mx-auto">{{ t('fiverr.cta.subtitle') }}</p>
|
||||
<UButton
|
||||
:to="siteConfig.fiverr.profileUrl"
|
||||
target="_blank"
|
||||
external
|
||||
size="xl"
|
||||
color="white"
|
||||
trailing-icon="i-lucide-external-link"
|
||||
class="font-semibold"
|
||||
>
|
||||
{{ t('fiverr.cta.button') }}
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<CTASection
|
||||
:title="t('fiverr.cta.title')"
|
||||
:subtitle="t('fiverr.cta.subtitle')"
|
||||
:primary-text="t('fiverr.cta.button')"
|
||||
:primary-to="siteConfig.fiverr.profileUrl"
|
||||
:secondary-text="t('fiverr.profileCta')"
|
||||
secondary-to="/contact"
|
||||
external
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
+9
-13
@@ -23,7 +23,7 @@ useHead({
|
||||
'@graph': [
|
||||
{
|
||||
'@type': 'Person',
|
||||
name: 'Killian Dalcin',
|
||||
name: "Killian' DAL-CIN",
|
||||
url: 'https://killiandalcin.fr',
|
||||
jobTitle: 'Developpeur Full Stack Freelance',
|
||||
email: 'contact@killiandalcin.fr',
|
||||
@@ -35,14 +35,14 @@ useHead({
|
||||
},
|
||||
{
|
||||
'@type': 'ProfessionalService',
|
||||
name: 'Killian Dalcin - Developpeur Full Stack',
|
||||
name: "Killian' DAL-CIN - Developpeur Full Stack",
|
||||
url: 'https://killiandalcin.fr',
|
||||
logo: 'https://killiandalcin.fr/images/logo.webp',
|
||||
priceRange: '$$$',
|
||||
areaServed: 'Worldwide',
|
||||
logo: 'https://killiandalcin.fr/images/logo.webp',
|
||||
priceRange: '$$$',
|
||||
areaServed: 'Worldwide',
|
||||
},
|
||||
],
|
||||
}),
|
||||
}),
|
||||
},
|
||||
],
|
||||
})
|
||||
@@ -54,7 +54,7 @@ useHead({
|
||||
<HeroSection />
|
||||
|
||||
<!-- Featured Projects Section -->
|
||||
<div class="bg-gray-50 dark:bg-gray-900/30">
|
||||
<div class="relative bg-gray-50/50 dark:bg-gray-900/20">
|
||||
<FeaturedProjectsSection />
|
||||
</div>
|
||||
|
||||
@@ -62,16 +62,12 @@ useHead({
|
||||
<ServicesSection />
|
||||
|
||||
<!-- Testimonials Section -->
|
||||
<div class="bg-gray-50 dark:bg-gray-900/30">
|
||||
<div class="relative bg-gray-50/50 dark:bg-gray-900/20">
|
||||
<TestimonialsSection />
|
||||
</div>
|
||||
|
||||
<!-- FAQ Section -->
|
||||
<FAQSection
|
||||
:faqs="homeFAQs"
|
||||
:title="t('faq.title')"
|
||||
:subtitle="t('faq.subtitle')"
|
||||
/>
|
||||
<FAQSection :faqs="homeFAQs" :title="t('faq.title')" :subtitle="t('faq.subtitle')" />
|
||||
|
||||
<!-- CTA Section -->
|
||||
<CTASection />
|
||||
|
||||
+117
-99
@@ -30,107 +30,113 @@ useSeoMeta({
|
||||
|
||||
<template>
|
||||
<div v-if="project">
|
||||
<!-- Back navigation -->
|
||||
<div class="bg-gray-50 dark:bg-gray-900/30 border-b border-gray-200 dark:border-gray-800">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
||||
<UButton
|
||||
variant="ghost"
|
||||
icon="i-lucide-arrow-left"
|
||||
to="/projects"
|
||||
size="sm"
|
||||
class="text-gray-500 hover:text-gray-900 dark:hover:text-white"
|
||||
>
|
||||
{{ t('projects.projectDetail.backToProjects') }}
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Full-width hero image -->
|
||||
<section class="relative overflow-hidden">
|
||||
<!-- Hero image with overlay -->
|
||||
<div class="relative h-[40vh] sm:h-[50vh] lg:h-[60vh]">
|
||||
<NuxtImg
|
||||
v-if="project.image"
|
||||
:src="project.image"
|
||||
:alt="project.title"
|
||||
class="w-full h-full object-cover"
|
||||
format="webp"
|
||||
loading="eager"
|
||||
/>
|
||||
<!-- Gradient overlay -->
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-white via-white/40 to-transparent dark:from-gray-950 dark:via-gray-950/40 dark:to-transparent" />
|
||||
<div class="absolute inset-0 bg-gradient-to-r from-white/60 to-transparent dark:from-gray-950/60 dark:to-transparent" />
|
||||
|
||||
<!-- Hero section -->
|
||||
<section class="bg-gray-50 dark:bg-gray-900/30 pb-16 pt-8">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-10 lg:gap-16 items-center">
|
||||
<!-- Project Image -->
|
||||
<div class="rounded-2xl overflow-hidden border border-gray-200 dark:border-gray-800 shadow-lg">
|
||||
<NuxtImg
|
||||
v-if="project.image"
|
||||
:src="project.image"
|
||||
:alt="project.title"
|
||||
class="w-full h-auto object-cover"
|
||||
format="webp"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
<!-- Back button (floating) -->
|
||||
<div class="absolute top-6 left-4 sm:left-6 lg:left-8 z-20">
|
||||
<UButton
|
||||
variant="solid"
|
||||
color="neutral"
|
||||
icon="i-lucide-arrow-left"
|
||||
to="/projects"
|
||||
size="sm"
|
||||
class="shadow-lg backdrop-blur-sm"
|
||||
>
|
||||
{{ t('projects.projectDetail.backToProjects') }}
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<!-- Project Info -->
|
||||
<div class="flex flex-col justify-center space-y-6">
|
||||
<div class="flex items-center gap-3">
|
||||
<!-- Title overlay at bottom -->
|
||||
<div class="absolute bottom-0 left-0 right-0 z-10 px-4 sm:px-6 lg:px-8 pb-10">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<UBadge v-if="project.category" variant="subtle" size="md">{{ project.category }}</UBadge>
|
||||
<span v-if="project.date" class="text-sm text-gray-400 dark:text-gray-500 font-medium">{{ project.date }}</span>
|
||||
</div>
|
||||
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-white">{{ project.title }}</h1>
|
||||
<p class="text-lg text-gray-500 dark:text-gray-400 leading-relaxed">{{ project.description }}</p>
|
||||
|
||||
<!-- CTA Buttons -->
|
||||
<div class="flex flex-wrap gap-3 pt-2">
|
||||
<UButton
|
||||
v-if="project.demoUrl"
|
||||
:to="project.demoUrl"
|
||||
target="_blank"
|
||||
icon="i-lucide-external-link"
|
||||
size="lg"
|
||||
class="font-semibold"
|
||||
>
|
||||
{{ t('projects.projectDetail.viewDemo') }}
|
||||
</UButton>
|
||||
|
||||
<UButton
|
||||
v-if="project.githubUrl"
|
||||
:to="project.githubUrl"
|
||||
target="_blank"
|
||||
variant="soft"
|
||||
icon="i-lucide-github"
|
||||
size="lg"
|
||||
>
|
||||
{{ t('projects.projectDetail.sourceCode') }}
|
||||
</UButton>
|
||||
|
||||
<UButton
|
||||
v-for="button in project.buttons"
|
||||
:key="button.title"
|
||||
:to="button.link"
|
||||
target="_blank"
|
||||
variant="outline"
|
||||
icon="i-lucide-external-link"
|
||||
size="lg"
|
||||
>
|
||||
{{ button.title }}
|
||||
</UButton>
|
||||
<span v-if="project.date" class="text-sm text-gray-500 dark:text-gray-400 font-mono">{{ project.date }}</span>
|
||||
</div>
|
||||
<h1 class="text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 dark:text-white max-w-3xl tracking-tight">{{ project.title }}</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Content -->
|
||||
<section class="py-16 px-4">
|
||||
<!-- Content area -->
|
||||
<section class="py-12 md:py-16 px-4 sm:px-6 lg:px-8">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-10 lg:gap-16">
|
||||
<!-- Main Content -->
|
||||
<div class="lg:col-span-2 space-y-16">
|
||||
<!-- About -->
|
||||
<div class="lg:col-span-2 space-y-14">
|
||||
<!-- Description -->
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-5">{{ t('projects.projectDetail.aboutProject') }}</h2>
|
||||
<p class="text-lg sm:text-xl text-gray-600 dark:text-gray-300 leading-relaxed mb-8">{{ project.description }}</p>
|
||||
|
||||
<!-- CTA Buttons -->
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<UButton
|
||||
v-if="project.demoUrl"
|
||||
:to="project.demoUrl"
|
||||
target="_blank"
|
||||
icon="i-lucide-external-link"
|
||||
size="lg"
|
||||
class="font-semibold"
|
||||
>
|
||||
{{ t('projects.projectDetail.viewDemo') }}
|
||||
</UButton>
|
||||
|
||||
<UButton
|
||||
v-if="project.githubUrl"
|
||||
:to="project.githubUrl"
|
||||
target="_blank"
|
||||
variant="soft"
|
||||
icon="i-lucide-github"
|
||||
size="lg"
|
||||
>
|
||||
{{ t('projects.projectDetail.sourceCode') }}
|
||||
</UButton>
|
||||
|
||||
<UButton
|
||||
v-for="button in project.buttons"
|
||||
:key="button.title"
|
||||
:to="button.link"
|
||||
target="_blank"
|
||||
variant="outline"
|
||||
icon="i-lucide-external-link"
|
||||
size="lg"
|
||||
>
|
||||
{{ button.title }}
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- About -->
|
||||
<div class="rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/60 dark:bg-gray-900/40 backdrop-blur-sm p-7 sm:p-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-5 flex items-center gap-3">
|
||||
<div class="w-1 h-6 rounded-full bg-brand-500" />
|
||||
{{ t('projects.projectDetail.aboutProject') }}
|
||||
</h2>
|
||||
<p class="text-gray-500 dark:text-gray-400 leading-relaxed text-lg">
|
||||
{{ project.longDescription || project.description }}
|
||||
</p>
|
||||
|
||||
<!-- Features -->
|
||||
<div v-if="project.features" class="mt-8">
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-4">{{ t('projects.projectDetail.keyFeatures') }}</h3>
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-5">{{ t('projects.projectDetail.keyFeatures') }}</h3>
|
||||
<ul class="space-y-3">
|
||||
<li v-for="feature in project.features" :key="feature" class="flex items-start gap-3">
|
||||
<div class="w-6 h-6 rounded-full bg-brand-500/10 flex items-center justify-center shrink-0 mt-0.5">
|
||||
<li v-for="feature in project.features" :key="feature" class="flex items-start gap-3 group">
|
||||
<div class="w-6 h-6 rounded-lg bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center shrink-0 mt-0.5 group-hover:bg-brand-500/20 transition-colors">
|
||||
<UIcon name="i-lucide-check" class="text-brand-500 w-3.5 h-3.5" />
|
||||
</div>
|
||||
<span class="text-gray-600 dark:text-gray-300">{{ feature }}</span>
|
||||
@@ -140,27 +146,33 @@ useSeoMeta({
|
||||
</div>
|
||||
|
||||
<!-- Technologies -->
|
||||
<div v-if="project.technologies.length">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-5">{{ t('projects.projectDetail.technologiesUsed') }}</h2>
|
||||
<div v-if="project.technologies.length" class="rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/60 dark:bg-gray-900/40 backdrop-blur-sm p-7 sm:p-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-5 flex items-center gap-3">
|
||||
<div class="w-1 h-6 rounded-full bg-brand-500" />
|
||||
{{ t('projects.projectDetail.technologiesUsed') }}
|
||||
</h2>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<TechBadge v-for="tech in project.technologies" :key="tech" :tech="tech" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gallery Thumbnails -->
|
||||
<div v-if="project.gallery?.length">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-5">{{ t('projects.projectDetail.gallery') }}</h2>
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 gap-4">
|
||||
<div v-if="project.gallery?.length" class="rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/60 dark:bg-gray-900/40 backdrop-blur-sm p-7 sm:p-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-5 flex items-center gap-3">
|
||||
<div class="w-1 h-6 rounded-full bg-brand-500" />
|
||||
{{ t('projects.projectDetail.gallery') }}
|
||||
</h2>
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 gap-3">
|
||||
<button
|
||||
v-for="(image, index) in project.gallery"
|
||||
:key="index"
|
||||
class="relative rounded-xl overflow-hidden group cursor-pointer border border-gray-200 dark:border-gray-800"
|
||||
class="relative rounded-xl overflow-hidden group cursor-pointer border border-gray-200/80 dark:border-gray-800/50 aspect-video"
|
||||
@click="galleryRef?.openGallery(index)"
|
||||
>
|
||||
<NuxtImg
|
||||
:src="image"
|
||||
:alt="`${project.title} - Image ${index + 1}`"
|
||||
class="w-full h-32 object-cover transition-transform duration-300 group-hover:scale-105"
|
||||
class="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
|
||||
loading="lazy"
|
||||
format="webp"
|
||||
/>
|
||||
@@ -173,17 +185,20 @@ useSeoMeta({
|
||||
</div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<aside class="space-y-6">
|
||||
<aside class="sticky top-24 space-y-6">
|
||||
<!-- Project Info Card -->
|
||||
<div class="rounded-2xl border border-gray-200 dark:border-gray-800 bg-gray-50 dark:bg-gray-900 p-6 sticky top-24">
|
||||
<h3 class="font-bold text-gray-900 dark:text-white mb-5">{{ t('projects.projectDetail.projectInfo') }}</h3>
|
||||
<div class="rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/60 dark:bg-gray-900/40 backdrop-blur-sm p-6">
|
||||
<h3 class="font-bold text-gray-900 dark:text-white mb-5 flex items-center gap-2">
|
||||
<UIcon name="i-lucide-info" class="text-brand-500 w-4 h-4" />
|
||||
{{ t('projects.projectDetail.projectInfo') }}
|
||||
</h3>
|
||||
|
||||
<div class="space-y-4 text-sm">
|
||||
<div v-if="project.date" class="flex justify-between items-center py-2 border-b border-gray-200 dark:border-gray-800">
|
||||
<div v-if="project.date" class="flex justify-between items-center py-3 border-b border-gray-200/60 dark:border-gray-800/40">
|
||||
<span class="text-gray-500 dark:text-gray-400">{{ t('projects.projectDetail.date') }}</span>
|
||||
<span class="font-semibold text-gray-900 dark:text-white">{{ project.date }}</span>
|
||||
<span class="font-semibold text-gray-900 dark:text-white font-mono text-xs">{{ project.date }}</span>
|
||||
</div>
|
||||
<div v-if="project.category" class="flex justify-between items-center py-2">
|
||||
<div v-if="project.category" class="flex justify-between items-center py-3">
|
||||
<span class="text-gray-500 dark:text-gray-400">{{ t('projects.projectDetail.category') }}</span>
|
||||
<UBadge variant="subtle" size="xs">{{ project.category }}</UBadge>
|
||||
</div>
|
||||
@@ -191,14 +206,17 @@ useSeoMeta({
|
||||
</div>
|
||||
|
||||
<!-- Related Projects -->
|
||||
<div v-if="relatedProjects.length > 0" class="rounded-2xl border border-gray-200 dark:border-gray-800 bg-gray-50 dark:bg-gray-900 p-6">
|
||||
<h3 class="font-bold text-gray-900 dark:text-white mb-5">{{ t('projects.projectDetail.relatedProjects') }}</h3>
|
||||
<div class="space-y-4">
|
||||
<div v-if="relatedProjects.length > 0" class="rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/60 dark:bg-gray-900/40 backdrop-blur-sm p-6">
|
||||
<h3 class="font-bold text-gray-900 dark:text-white mb-5 flex items-center gap-2">
|
||||
<UIcon name="i-lucide-layers" class="text-brand-500 w-4 h-4" />
|
||||
{{ t('projects.projectDetail.relatedProjects') }}
|
||||
</h3>
|
||||
<div class="space-y-3">
|
||||
<NuxtLink
|
||||
v-for="related in relatedProjects"
|
||||
:key="related.id"
|
||||
:to="`/project/${related.id}`"
|
||||
class="flex gap-3 p-3 rounded-xl hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors group"
|
||||
class="flex gap-3 p-3 rounded-xl border border-transparent hover:border-brand-500/20 hover:bg-brand-500/5 transition-all duration-200 group"
|
||||
>
|
||||
<NuxtImg
|
||||
v-if="related.image"
|
||||
@@ -211,7 +229,7 @@ useSeoMeta({
|
||||
/>
|
||||
<div class="min-w-0">
|
||||
<p class="font-semibold text-sm text-gray-900 dark:text-white truncate group-hover:text-brand-500 transition-colors">{{ related.title }}</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400 line-clamp-2 mt-0.5">{{ related.description }}</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400 line-clamp-2 mt-1">{{ related.description }}</p>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
+25
-22
@@ -53,37 +53,40 @@ function resetFilters() {
|
||||
<template>
|
||||
<div>
|
||||
<!-- Hero -->
|
||||
<section class="pt-16 pb-12 px-4 bg-gray-50 dark:bg-gray-900/30">
|
||||
<div class="max-w-7xl mx-auto text-center">
|
||||
<span class="text-sm font-semibold text-brand-500 dark:text-brand-400 uppercase tracking-wider">Portfolio</span>
|
||||
<h1 class="text-4xl sm:text-5xl font-bold mt-2 mb-4 text-gray-900 dark:text-white">{{ t('projects.title') }}</h1>
|
||||
<p class="text-lg text-gray-500 dark:text-gray-400 max-w-2xl mx-auto">{{ t('projects.subtitle') }}</p>
|
||||
<section class="relative pt-20 pb-16 px-4 sm:px-6 lg:px-8 overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gray-50/80 dark:bg-gray-900/40" aria-hidden="true" />
|
||||
<div class="absolute top-0 left-1/2 -translate-x-1/2 w-[800px] h-[400px] bg-brand-500/5 dark:bg-brand-500/8 rounded-full blur-3xl pointer-events-none" aria-hidden="true" />
|
||||
|
||||
<div class="relative z-10 max-w-7xl mx-auto text-center">
|
||||
<span class="font-mono text-sm text-brand-500 dark:text-brand-400 tracking-wider">// portfolio</span>
|
||||
<h1 class="text-4xl sm:text-5xl lg:text-6xl font-bold mt-3 mb-5 bg-gradient-to-r from-gray-900 via-gray-800 to-gray-600 dark:from-white dark:via-gray-200 dark:to-gray-500 bg-clip-text text-transparent">{{ t('projects.title') }}</h1>
|
||||
<p class="text-lg sm:text-xl text-gray-500 dark:text-gray-400 max-w-2xl mx-auto leading-relaxed">{{ t('projects.subtitle') }}</p>
|
||||
|
||||
<!-- Stats -->
|
||||
<div class="flex justify-center gap-10 mt-10">
|
||||
<div class="flex justify-center gap-8 sm:gap-12 mt-12">
|
||||
<div class="text-center">
|
||||
<p class="text-3xl font-extrabold text-brand-500 dark:text-brand-400">{{ totalProjects }}</p>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">{{ t('nav.projects') }}</p>
|
||||
<p class="text-3xl sm:text-4xl font-black bg-gradient-to-b from-brand-400 to-brand-600 bg-clip-text text-transparent">{{ totalProjects }}</p>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 mt-2 font-medium">{{ t('nav.projects') }}</p>
|
||||
</div>
|
||||
<div class="w-px bg-gray-200 dark:bg-gray-800" />
|
||||
<div class="w-px bg-gradient-to-b from-transparent via-gray-300 dark:via-gray-700 to-transparent" />
|
||||
<div class="text-center">
|
||||
<p class="text-3xl font-extrabold text-brand-500 dark:text-brand-400">{{ featuredCount }}</p>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">{{ t('home.featuredProjects.title') }}</p>
|
||||
<p class="text-3xl sm:text-4xl font-black bg-gradient-to-b from-brand-400 to-brand-600 bg-clip-text text-transparent">{{ featuredCount }}</p>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 mt-2 font-medium">{{ t('home.featuredProjects.title') }}</p>
|
||||
</div>
|
||||
<div class="w-px bg-gray-200 dark:bg-gray-800" />
|
||||
<div class="w-px bg-gradient-to-b from-transparent via-gray-300 dark:via-gray-700 to-transparent" />
|
||||
<div class="text-center">
|
||||
<p class="text-3xl font-extrabold text-brand-500 dark:text-brand-400">{{ categories.length - 1 }}</p>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">{{ t('projects.categories.all') }}</p>
|
||||
<p class="text-3xl sm:text-4xl font-black bg-gradient-to-b from-brand-400 to-brand-600 bg-clip-text text-transparent">{{ categories.length - 1 }}</p>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 mt-2 font-medium">{{ t('projects.categories.all') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Filters & Grid -->
|
||||
<section class="py-12 px-4">
|
||||
<section class="py-16 md:py-20 px-4 sm:px-6 lg:px-8">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<!-- Filter bar -->
|
||||
<div class="flex flex-col sm:flex-row gap-4 items-start sm:items-center mb-10 p-4 rounded-2xl bg-gray-50 dark:bg-gray-900/50 border border-gray-200 dark:border-gray-800">
|
||||
<div class="flex flex-col sm:flex-row gap-4 items-start sm:items-center mb-12 p-4 sm:p-5 rounded-2xl border border-gray-200/80 dark:border-gray-800/50 bg-white/60 dark:bg-gray-900/40 backdrop-blur-sm">
|
||||
<UInput
|
||||
v-model="searchQuery"
|
||||
icon="i-lucide-search"
|
||||
@@ -108,18 +111,18 @@ function resetFilters() {
|
||||
</div>
|
||||
|
||||
<!-- Projects Grid -->
|
||||
<div v-if="filteredProjects.length > 0" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-8">
|
||||
<div v-if="filteredProjects.length > 0" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5 lg:gap-6">
|
||||
<ProjectCard v-for="project in filteredProjects" :key="project.id" :project="project" />
|
||||
</div>
|
||||
|
||||
<!-- Empty State -->
|
||||
<div v-else class="text-center py-24">
|
||||
<div class="w-16 h-16 mx-auto mb-6 rounded-2xl bg-gray-100 dark:bg-gray-800 flex items-center justify-center">
|
||||
<div v-else class="text-center py-32">
|
||||
<div class="w-16 h-16 mx-auto mb-6 rounded-2xl bg-gray-100 dark:bg-gray-800/60 border border-gray-200/80 dark:border-gray-700/30 flex items-center justify-center">
|
||||
<UIcon name="i-lucide-search-x" class="text-2xl text-gray-400" />
|
||||
</div>
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-2">{{ t('projects.noResults.title') }}</h3>
|
||||
<p class="text-gray-500 dark:text-gray-400 mb-8 max-w-md mx-auto">{{ t('projects.noResults.description') }}</p>
|
||||
<UButton @click="resetFilters" variant="soft" size="md">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-3">{{ t('projects.noResults.title') }}</h3>
|
||||
<p class="text-gray-500 dark:text-gray-400 mb-8 max-w-md mx-auto leading-relaxed">{{ t('projects.noResults.description') }}</p>
|
||||
<UButton @click="resetFilters" variant="soft" size="md" icon="i-lucide-rotate-ccw">
|
||||
{{ t('common.reset') }}
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user