92 lines
3.3 KiB
Vue
92 lines
3.3 KiB
Vue
<template>
|
||
<section id="projects" class="py-24 px-4">
|
||
<div class="max-w-4xl mx-auto">
|
||
<div class="section-hidden" ref="sectionRef">
|
||
<h2 class="text-3xl md:text-4xl font-bold text-white mb-4">
|
||
Проекты
|
||
</h2>
|
||
<div class="w-16 h-1 bg-indigo-500 mb-10 rounded-full" />
|
||
<div class="grid md:grid-cols-2 gap-6">
|
||
<UCard
|
||
v-for="project in projects"
|
||
:key="project.title"
|
||
class="bg-gray-900 border-gray-800 hover:border-indigo-500 transition-colors duration-300"
|
||
>
|
||
<div class="space-y-3">
|
||
<div class="flex items-start justify-between">
|
||
<h3 class="text-white font-semibold text-lg">{{ project.title }}</h3>
|
||
<UBadge :color="project.statusColor" variant="soft" size="sm">
|
||
{{ project.status }}
|
||
</UBadge>
|
||
</div>
|
||
<p class="text-gray-400 text-sm leading-relaxed">{{ project.description }}</p>
|
||
<div class="flex flex-wrap gap-2 pt-1">
|
||
<UBadge
|
||
v-for="tech in project.stack"
|
||
:key="tech"
|
||
color="neutral"
|
||
variant="outline"
|
||
size="xs"
|
||
>
|
||
{{ tech }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
</UCard>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
const sectionRef = ref<HTMLElement | null>(null);
|
||
|
||
const projects = [
|
||
{
|
||
title: 'E-Commerce Platform',
|
||
description: 'Полноценная платформа электронной коммерции с микросервисной архитектурой, real-time уведомлениями и AI-рекомендациями.',
|
||
stack: ['NestJS', 'Nuxt 3', 'PostgreSQL', 'Redis', 'Docker'],
|
||
status: 'Production',
|
||
statusColor: 'success' as const,
|
||
},
|
||
{
|
||
title: 'DevOps Dashboard',
|
||
description: 'Мониторинговый дашборд для CI/CD пайплайнов с метриками, алертами и историей деплоев.',
|
||
stack: ['Vue 3', 'Node.js', 'InfluxDB', 'Grafana', 'K8s'],
|
||
status: 'Production',
|
||
statusColor: 'success' as const,
|
||
},
|
||
{
|
||
title: 'AI Content Generator',
|
||
description: 'Инструмент генерации контента на основе OpenAI API с кастомными промптами и экспортом.',
|
||
stack: ['Nuxt 3', 'NestJS', 'OpenAI', 'TypeScript'],
|
||
status: 'Beta',
|
||
statusColor: 'warning' as const,
|
||
},
|
||
{
|
||
title: 'Real-Time Chat',
|
||
description: 'Мессенджер с WebSocket, поддержкой медиафайлов, сквозным шифрованием и мобильным приложением.',
|
||
stack: ['NestJS', 'Socket.io', 'React Native', 'MongoDB'],
|
||
status: 'WIP',
|
||
statusColor: 'info' as const,
|
||
},
|
||
];
|
||
|
||
onMounted(() => {
|
||
const observer = new IntersectionObserver(
|
||
(entries) => {
|
||
entries.forEach((entry) => {
|
||
if (entry.isIntersecting) {
|
||
entry.target.classList.remove('section-hidden');
|
||
entry.target.classList.add('section-visible');
|
||
observer.unobserve(entry.target);
|
||
}
|
||
});
|
||
},
|
||
{ threshold: 0.1 },
|
||
);
|
||
if (sectionRef.value) observer.observe(sectionRef.value);
|
||
});
|
||
</script>
|