init
This commit is contained in:
91
frontend/app/components/ProjectsSection.vue
Normal file
91
frontend/app/components/ProjectsSection.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user