feat: add base design

This commit is contained in:
2026-01-02 10:21:37 +03:00
parent 4a6f0d83ce
commit 202ac4627f
30 changed files with 3396 additions and 132 deletions

View File

@@ -0,0 +1,71 @@
"use client";
import { SectionContainer } from "@/features/section-container";
import { SectionHeader } from "@/features/section-header";
import { ComparisonItem } from "@/features/comparison-item";
import { FileText, Workflow, Mail } from "lucide-react";
const comparisons = [
{
before: {
title: "Ручное управление",
description: "Потеря времени на рутинные задачи и отслеживание статусов",
icon: FileText,
},
after: {
title: "Автоматизация",
description: "Автоматические уведомления, дедлайны и распределение задач",
icon: Workflow,
},
},
{
before: {
title: "Хаос в задачах",
description: "Задачи разбросаны по разным инструментам и чатам",
},
after: {
title: "Структурированный процесс",
description: "Все задачи в одном месте с четкой структурой и приоритетами",
},
},
{
before: {
title: "Email-цепочки",
description: "Потерянные сообщения и долгие согласования",
icon: Mail,
},
after: {
title: "Централизованное общение",
description: "Вся коммуникация по проекту в контексте задач",
},
},
];
/**
* Comparison Section - секция сравнения "до/после"
*/
export function ComparisonSection() {
return (
<SectionContainer id="comparison" background="gradient">
<SectionHeader
subtitle="До и после"
title="Как TaskFlow меняет работу"
description="Сравните привычный подход с нашим решением"
withGradient
/>
<div className="space-y-6">
{comparisons.map((comparison, index) => (
<ComparisonItem
key={index}
{...comparison}
variant="overlay"
/>
))}
</div>
</SectionContainer>
);
}

View File

@@ -0,0 +1,80 @@
"use client";
import { SectionContainer } from "@/features/section-container";
import { GradientBackground } from "@/features/gradient-background";
import { Button } from "@/shared/ui/button";
import { Input } from "@/shared/ui/input";
import { motion } from "framer-motion";
import { ArrowRight, Sparkles } from "lucide-react";
import Link from "next/link";
/**
* CTA Section - финальный призыв к действию
*/
export function CtaSection() {
return (
<SectionContainer className="relative">
<GradientBackground variant="mesh" opacity={0.4} />
<div className="relative z-10 max-w-4xl mx-auto text-center">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6 }}
className="space-y-8"
>
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-[var(--feature-accent)]/10 border border-[var(--feature-accent)]/20">
<Sparkles className="w-4 h-4 text-[var(--feature-accent)]" />
<span className="text-sm font-medium text-[var(--feature-accent)]">
Начните работать эффективнее уже сегодня
</span>
</div>
<h2 className="text-4xl sm:text-5xl lg:text-6xl font-bold tracking-tight">
Готовы{" "}
<span className="text-gradient">трансформировать</span>
<br />
работу вашей команды?
</h2>
<p className="text-lg lg:text-xl text-muted-foreground max-w-2xl mx-auto">
Присоединяйтесь к тысячам команд, которые уже используют TaskFlow
для достижения своих целей быстрее и эффективнее.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center items-center max-w-md mx-auto">
<Input
type="email"
placeholder="Ваш email"
className="h-12"
/>
<Button size="lg" className="w-full sm:w-auto group">
Попробовать бесплатно
<ArrowRight className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-1" />
</Button>
</div>
<p className="text-sm text-muted-foreground">
14 дней бесплатно Кредитная карта не требуется Отмените в любое время
</p>
<div className="pt-8 flex flex-wrap items-center justify-center gap-8 text-sm text-muted-foreground">
<div className="flex items-center gap-2">
Настройка за 5 минут
</div>
<div className="flex items-center gap-2">
Поддержка 24/7
</div>
<div className="flex items-center gap-2">
Безопасность данных
</div>
</div>
</motion.div>
</div>
</SectionContainer>
);
}

View File

@@ -0,0 +1,99 @@
"use client";
import { SectionContainer } from "@/features/section-container";
import { SectionHeader } from "@/features/section-header";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/shared/ui/accordion";
const faqs = [
{
question: "Как начать работу с TaskFlow?",
answer:
"Просто зарегистрируйтесь на сайте, создайте свой первый проект и пригласите команду. Настройка займет не более 5 минут. Мы предлагаем 14-дневный бесплатный пробный период для всех планов.",
},
{
question: "Могу ли я изменить тариф в любое время?",
answer:
"Да, вы можете повысить или понизить свой тариф в любое время. При повышении тарифа вы сразу получите доступ к новым функциям. При понижении изменения вступят в силу со следующего платежного периода.",
},
{
question: "Есть ли бесплатный период?",
answer:
"Да! Мы предлагаем 14-дневную бесплатную пробную версию для всех платных планов. Кредитная карта не требуется для начала пробного периода. План Free доступен всегда без ограничений по времени.",
},
{
question: "Как работает поддержка?",
answer:
"Для пользователей Free доступна поддержка по email. Пользователи Pro получают приоритетную поддержку по email и чату. Клиенты Enterprise имеют доступ к выделенному менеджеру и поддержке 24/7.",
},
{
question: "Безопасны ли мои данные?",
answer:
"Абсолютно! Мы используем шифрование на уровне банков (SSL/TLS), регулярно делаем резервные копии и храним данные в защищенных дата-центрах. Мы соответствуем стандартам GDPR и SOC 2.",
},
{
question: "Можно ли интегрировать TaskFlow с другими сервисами?",
answer:
"Да! TaskFlow интегрируется с более чем 50 популярными сервисами, включая Slack, GitHub, Jira, Google Calendar и многими другими. Пользователи Enterprise также получают доступ к API для создания собственных интеграций.",
},
{
question: "Доступно ли мобильное приложение?",
answer:
"Да, у нас есть нативные приложения для iOS и Android. Все функции доступны на мобильных устройствах, и данные синхронизируются в реальном времени между всеми платформами.",
},
{
question: "Как отменить подписку?",
answer:
"Вы можете отменить подписку в любое время через настройки аккаунта. При отмене вы сохраните доступ ко всем функциям до конца оплаченного периода. Никаких штрафов за отмену подписки нет.",
},
];
/**
* FAQ Section - секция с частыми вопросами
*/
export function FaqSection() {
return (
<SectionContainer id="faq" background="muted">
<SectionHeader
subtitle="FAQ"
title="Частые вопросы"
description="Ответы на популярные вопросы о TaskFlow"
withGradient
/>
<div className="max-w-3xl mx-auto">
<Accordion type="single" collapsible className="w-full">
{faqs.map((faq, index) => (
<AccordionItem key={index} value={`item-${index}`}>
<AccordionTrigger className="text-left">
{faq.question}
</AccordionTrigger>
<AccordionContent className="text-muted-foreground">
{faq.answer}
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
<div className="mt-12 text-center">
<p className="text-muted-foreground mb-4">
Не нашли ответ на свой вопрос?
</p>
<a
href="#"
className="text-[var(--feature-accent)] font-medium hover:underline"
>
Свяжитесь с нашей поддержкой
</a>
</div>
</SectionContainer>
);
}

View File

@@ -0,0 +1,87 @@
"use client";
import { SectionContainer } from "@/features/section-container";
import { SectionHeader } from "@/features/section-header";
import { FeatureCard } from "@/features/feature-card";
import { motion } from "framer-motion";
import { staggerContainer, staggerItem } from "@/shared/hooks/use-scroll-animation";
import {
Zap,
Users,
BarChart3,
Puzzle,
Shield,
Headphones,
} from "lucide-react";
const features = [
{
icon: Zap,
title: "Быстрый старт",
description:
"Начните работу за 5 минут. Интуитивный интерфейс и простая настройка.",
},
{
icon: Users,
title: "Командная работа",
description:
"Пригласите коллег и работайте вместе в реальном времени над проектами.",
},
{
icon: BarChart3,
title: "Аналитика",
description:
"Отслеживайте прогресс в реальном времени с подробными отчетами и дашбордами.",
},
{
icon: Puzzle,
title: "Интеграции",
description:
"Подключите любимые инструменты: Slack, GitHub, Jira и еще более 50 сервисов.",
},
{
icon: Shield,
title: "Безопасность",
description:
"Защита данных на уровне банков с шифрованием и регулярными бэкапами.",
},
{
icon: Headphones,
title: "Поддержка 24/7",
description:
"Наша команда всегда готова помочь вам в любое время дня и ночи.",
},
];
/**
* Features Section - секция с возможностями/преимуществами
*/
export function FeaturesSection() {
return (
<SectionContainer id="features">
<SectionHeader
subtitle="Возможности"
title="Все что нужно для вашей команды"
description="Мощные инструменты для эффективной работы в одном месте"
withGradient
/>
<motion.div
variants={staggerContainer}
initial="hidden"
whileInView="show"
viewport={{ once: true, margin: "-100px" }}
className="grid sm:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-8"
>
{features.map((feature) => (
<motion.div key={feature.title} variants={staggerItem}>
<FeatureCard {...feature} />
</motion.div>
))}
</motion.div>
</SectionContainer>
);
}

132
src/widgets/footer.tsx Normal file
View File

@@ -0,0 +1,132 @@
"use client";
import Link from "next/link";
import { Separator } from "@/shared/ui/separator";
import { Github, Twitter, Linkedin, Youtube } from "lucide-react";
const footerLinks = {
product: {
title: "Продукт",
links: [
{ name: "Возможности", href: "#features" },
{ name: "Тарифы", href: "#pricing" },
{ name: "Обновления", href: "#" },
{ name: "Roadmap", href: "#" },
],
},
company: {
title: "Компания",
links: [
{ name: "О нас", href: "#team" },
{ name: "Блог", href: "#" },
{ name: "Карьера", href: "#" },
{ name: "Пресс-кит", href: "#" },
],
},
resources: {
title: "Ресурсы",
links: [
{ name: "Документация", href: "#" },
{ name: "Помощь", href: "#faq" },
{ name: "API", href: "#" },
{ name: "Статус", href: "#" },
],
},
support: {
title: "Поддержка",
links: [
{ name: "Контакты", href: "#" },
{ name: "FAQ", href: "#faq" },
{ name: "Чат", href: "#" },
{ name: "Email", href: "mailto:support@taskflow.com" },
],
},
};
const socialLinks = [
{ name: "GitHub", icon: Github, href: "#" },
{ name: "Twitter", icon: Twitter, href: "#" },
{ name: "LinkedIn", icon: Linkedin, href: "#" },
{ name: "YouTube", icon: Youtube, href: "#" },
];
/**
* Footer - подвал сайта
*/
export function Footer() {
return (
<footer className="border-t bg-muted/50">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-12 lg:py-16">
{/* Main Footer Content */}
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-8 mb-12">
{/* Brand */}
<div className="col-span-2">
<Link href="/" className="inline-block mb-4">
<span className="text-2xl font-bold text-gradient">TaskFlow</span>
</Link>
<p className="text-sm text-muted-foreground mb-6 max-w-xs">
Современный инструмент для управления проектами и командной работы
</p>
{/* Social Links */}
<div className="flex gap-3">
{socialLinks.map((social) => (
<Link
key={social.name}
href={social.href}
className="p-2 rounded-lg bg-background hover:bg-[var(--feature-accent)]/10 hover:text-[var(--feature-accent)] transition-colors"
aria-label={social.name}
>
<social.icon className="w-5 h-5" />
</Link>
))}
</div>
</div>
{/* Links Columns */}
{Object.values(footerLinks).map((column) => (
<div key={column.title}>
<h3 className="font-semibold mb-4 text-sm">{column.title}</h3>
<ul className="space-y-3">
{column.links.map((link) => (
<li key={link.name}>
<Link
href={link.href}
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
>
{link.name}
</Link>
</li>
))}
</ul>
</div>
))}
</div>
<Separator className="mb-8" />
{/* Bottom Bar */}
<div className="flex flex-col md:flex-row justify-between items-center gap-4">
<p className="text-sm text-muted-foreground">
© {new Date().getFullYear()} TaskFlow. Все права защищены.
</p>
<div className="flex flex-wrap gap-6 text-sm text-muted-foreground">
<Link href="#" className="hover:text-foreground transition-colors">
Политика конфиденциальности
</Link>
<Link href="#" className="hover:text-foreground transition-colors">
Условия использования
</Link>
<Link href="#" className="hover:text-foreground transition-colors">
Cookies
</Link>
</div>
</div>
</div>
</footer>
);
}

View File

@@ -0,0 +1,69 @@
"use client";
import { SectionContainer } from "@/features/section-container";
import { SectionHeader } from "@/features/section-header";
import { PortfolioItem } from "@/features/portfolio-item";
const portfolioItems = [
{
image: "/api/placeholder/600/400",
title: "Dashboard",
description: "Полная аналитика проектов",
category: "Интерфейс",
},
{
image: "/api/placeholder/600/400",
title: "Kanban Board",
description: "Визуальное управление задачами",
category: "Функции",
},
{
image: "/api/placeholder/600/400",
title: "Team Collaboration",
description: "Совместная работа в реальном времени",
category: "Команда",
},
{
image: "/api/placeholder/600/400",
title: "Reports",
description: "Детальные отчеты о прогрессе",
category: "Аналитика",
},
{
image: "/api/placeholder/600/400",
title: "Mobile App",
description: "Работайте из любой точки мира",
category: "Мобайл",
},
{
image: "/api/placeholder/600/400",
title: "Integrations",
description: "Подключение к любимым сервисам",
category: "Интеграции",
},
];
/**
* Gallery Section - секция с примерами/скриншотами
*/
export function GallerySection() {
return (
<SectionContainer id="gallery">
<SectionHeader
subtitle="Галерея"
title="Посмотрите на возможности"
description="Скриншоты интерфейса и ключевых функций"
withGradient
/>
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-8">
{portfolioItems.map((item) => (
<PortfolioItem key={item.title} {...item} variant="card" />
))}
</div>
</SectionContainer>
);
}

146
src/widgets/header.tsx Normal file
View File

@@ -0,0 +1,146 @@
"use client";
import { useState, useEffect } from "react";
import { cn } from "@/shared/lib/utils";
import { Button } from "@/shared/ui/button";
import { Sheet, SheetContent, SheetTrigger } from "@/shared/ui/sheet";
import { Menu, X } from "lucide-react";
import Link from "next/link";
import { useTheme } from "next-themes";
import { Moon, Sun } from "lucide-react";
const navigation = [
{ name: "Возможности", href: "#features" },
{ name: "Преимущества", href: "#stats" },
{ name: "Как работает", href: "#how-it-works" },
{ name: "Тарифы", href: "#pricing" },
{ name: "FAQ", href: "#faq" },
];
/**
* Header с навигацией
* Sticky header с backdrop blur, мобильное меню, theme toggle
*/
export function Header() {
const [scrolled, setScrolled] = useState(false);
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const { theme, setTheme } = useTheme();
useEffect(() => {
const handleScroll = () => {
setScrolled(window.scrollY > 20);
};
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
const scrollToSection = (href: string) => {
const element = document.querySelector(href);
if (element) {
element.scrollIntoView({ behavior: "smooth" });
setMobileMenuOpen(false);
}
};
return (
<header
className={cn(
"sticky top-0 z-50 w-full transition-all duration-300",
scrolled
? "bg-background/80 backdrop-blur-lg border-b border-border shadow-sm"
: "bg-transparent"
)}
>
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16 lg:h-20">
{/* Logo */}
<Link href="/" className="flex items-center">
<span className="text-2xl font-bold text-gradient">TaskFlow</span>
</Link>
{/* Desktop Navigation */}
<nav className="hidden lg:flex items-center gap-8">
{navigation.map((item) => (
<button
key={item.name}
onClick={() => scrollToSection(item.href)}
className="text-sm font-medium text-muted-foreground hover:text-foreground transition-colors"
>
{item.name}
</button>
))}
</nav>
{/* Desktop Actions */}
<div className="hidden lg:flex items-center gap-4">
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
>
<Sun className="h-5 w-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-5 w-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
<Button variant="outline" asChild>
<Link href="#pricing">Войти</Link>
</Button>
<Button asChild>
<Link href="#pricing">Начать бесплатно</Link>
</Button>
</div>
{/* Mobile Menu */}
<div className="flex lg:hidden items-center gap-2">
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
>
<Sun className="h-5 w-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-5 w-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
<Sheet open={mobileMenuOpen} onOpenChange={setMobileMenuOpen}>
<SheetTrigger asChild>
<Button variant="ghost" size="icon">
{mobileMenuOpen ? (
<X className="h-6 w-6" />
) : (
<Menu className="h-6 w-6" />
)}
</Button>
</SheetTrigger>
<SheetContent side="right" className="w-full sm:w-80">
<nav className="flex flex-col gap-4 mt-8">
{navigation.map((item) => (
<button
key={item.name}
onClick={() => scrollToSection(item.href)}
className="text-lg font-medium text-left py-2 hover:text-[var(--feature-accent)] transition-colors"
>
{item.name}
</button>
))}
<div className="flex flex-col gap-3 mt-4 pt-4 border-t">
<Button variant="outline" asChild className="w-full">
<Link href="#pricing">Войти</Link>
</Button>
<Button asChild className="w-full">
<Link href="#pricing">Начать бесплатно</Link>
</Button>
</div>
</nav>
</SheetContent>
</Sheet>
</div>
</div>
</div>
</header>
);
}

View File

@@ -0,0 +1,167 @@
"use client";
import { SectionContainer } from "@/features/section-container";
import { GradientBackground } from "@/features/gradient-background";
import { Button } from "@/shared/ui/button";
import { motion } from "framer-motion";
import { ArrowRight, Play } from "lucide-react";
import Link from "next/link";
/**
* Hero Section - главная секция лендинга
* Варианты: centered, split (текст слева, визуал справа)
*/
export function HeroSection() {
return (
<SectionContainer className="relative min-h-[calc(100vh-5rem)] flex items-center">
<GradientBackground variant="animated" opacity={0.3} />
<div className="relative z-10 grid lg:grid-cols-2 gap-12 items-center w-full">
{/* Content */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className="space-y-8"
>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.1 }}
className="inline-block"
>
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-[var(--feature-accent)]/10 border border-[var(--feature-accent)]/20">
<span className="w-2 h-2 rounded-full bg-[var(--feature-accent)] animate-pulse" />
<span className="text-sm font-medium text-[var(--feature-accent)]">
Новый способ управления проектами
</span>
</div>
</motion.div>
<motion.h1
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.2 }}
className="text-4xl sm:text-5xl lg:text-6xl xl:text-7xl font-bold tracking-tight"
>
Управляйте проектами{" "}
<span className="text-gradient">быстрее и проще</span>
</motion.h1>
<motion.p
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.3 }}
className="text-lg lg:text-xl text-muted-foreground max-w-2xl"
>
Все инструменты для командной работы в одном месте. Начните работать
эффективнее уже сегодня.
</motion.p>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.4 }}
className="flex flex-wrap gap-4"
>
<Button size="lg" asChild className="group">
<Link href="#pricing">
Начать бесплатно
<ArrowRight className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-1" />
</Link>
</Button>
<Button size="lg" variant="outline" asChild>
<Link href="#how-it-works">
<Play className="mr-2 h-4 w-4" />
Посмотреть демо
</Link>
</Button>
</motion.div>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.6, delay: 0.5 }}
className="flex items-center gap-8 pt-4"
>
<div>
<div className="text-2xl font-bold text-gradient">10,000+</div>
<div className="text-sm text-muted-foreground">Пользователей</div>
</div>
<div className="h-12 w-px bg-border" />
<div>
<div className="text-2xl font-bold text-gradient">4.9</div>
<div className="text-sm text-muted-foreground">Рейтинг</div>
</div>
<div className="h-12 w-px bg-border" />
<div>
<div className="text-2xl font-bold text-gradient">99.9%</div>
<div className="text-sm text-muted-foreground">Uptime</div>
</div>
</motion.div>
</motion.div>
{/* Visual */}
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.8, delay: 0.3 }}
className="relative hidden lg:block"
>
<div className="relative aspect-square rounded-2xl bg-gradient-primary border border-border p-8 shadow-2xl">
<motion.div
animate={{
y: [0, -10, 0],
}}
transition={{
duration: 4,
repeat: Infinity,
ease: "easeInOut",
}}
className="absolute inset-0 flex items-center justify-center"
>
<div className="w-64 h-64 rounded-full bg-gradient-to-br from-[var(--gradient-from)] via-[var(--gradient-via)] to-[var(--gradient-to)] opacity-20 blur-3xl" />
</motion.div>
{/* Placeholder для мокапа/скриншота */}
<div className="relative z-10 h-full rounded-xl bg-card/50 backdrop-blur-sm border border-border flex items-center justify-center">
<span className="text-muted-foreground font-medium">
[Hero Image / Product Mockup]
</span>
</div>
</div>
{/* Floating elements */}
<motion.div
animate={{
y: [0, -20, 0],
rotate: [0, 5, 0],
}}
transition={{
duration: 5,
repeat: Infinity,
ease: "easeInOut",
}}
className="absolute -top-6 -right-6 w-32 h-32 rounded-2xl bg-[var(--feature-accent)]/10 border border-[var(--feature-accent)]/20 backdrop-blur-sm"
/>
<motion.div
animate={{
y: [0, 15, 0],
rotate: [0, -5, 0],
}}
transition={{
duration: 6,
repeat: Infinity,
ease: "easeInOut",
delay: 0.5,
}}
className="absolute -bottom-6 -left-6 w-24 h-24 rounded-full bg-[var(--gradient-via)]/10 border border-[var(--gradient-via)]/20 backdrop-blur-sm"
/>
</motion.div>
</div>
</SectionContainer>
);
}

View File

@@ -0,0 +1,64 @@
"use client";
import { SectionContainer } from "@/features/section-container";
import { SectionHeader } from "@/features/section-header";
import { StepCard } from "@/features/step-card";
import { motion } from "framer-motion";
import { UserPlus, FolderPlus, Users as UsersIcon, Rocket } from "lucide-react";
const steps = [
{
number: 1,
title: "Зарегистрируйтесь",
description: "Создайте аккаунт за 30 секунд. Кредитная карта не требуется.",
icon: UserPlus,
},
{
number: 2,
title: "Создайте проект",
description: "Настройте свой первый проект и добавьте задачи.",
icon: FolderPlus,
},
{
number: 3,
title: "Пригласите команду",
description: "Добавьте коллег и назначьте роли для совместной работы.",
icon: UsersIcon,
},
{
number: 4,
title: "Начните работать",
description: "Отслеживайте прогресс и достигайте целей быстрее.",
icon: Rocket,
},
];
/**
* How It Works Section - секция "Как это работает"
*/
export function HowItWorksSection() {
return (
<SectionContainer id="how-it-works">
<SectionHeader
subtitle="Как это работает"
title="Начните за 4 простых шага"
description="Настройка займет всего несколько минут"
withGradient
/>
<div className="relative">
{/* Connection line */}
<div className="hidden lg:block absolute top-8 left-0 right-0 h-0.5 bg-gradient-to-r from-[var(--gradient-from)] via-[var(--gradient-via)] to-[var(--gradient-to)] opacity-20" />
<div className="grid sm:grid-cols-2 lg:grid-cols-4 gap-8 lg:gap-6 relative">
{steps.map((step) => (
<StepCard key={step.number} {...step} variant="icon" />
))}
</div>
</div>
</SectionContainer>
);
}

View File

@@ -0,0 +1,90 @@
"use client";
import { SectionContainer } from "@/features/section-container";
import { SectionHeader } from "@/features/section-header";
import { PricingCard } from "@/features/pricing-card";
const pricingPlans = [
{
name: "Free",
price: 0,
description: "Для начала работы и малых команд",
features: [
{ text: "До 5 участников команды", included: true },
{ text: "До 10 проектов", included: true },
{ text: "Базовые отчеты", included: true },
{ text: "Email поддержка", included: true },
{ text: "Интеграции", included: false },
{ text: "Приоритетная поддержка", included: false },
{ text: "Кастомные роли", included: false },
],
ctaLabel: "Начать бесплатно",
ctaHref: "#",
},
{
name: "Pro",
price: 2900,
description: "Для растущих команд",
features: [
{ text: "До 50 участников команды", included: true },
{ text: "Неограниченные проекты", included: true },
{ text: "Расширенная аналитика", included: true },
{ text: "Email и чат поддержка", included: true },
{ text: "Все интеграции", included: true },
{ text: "Приоритетная поддержка", included: true },
{ text: "Кастомные роли", included: false },
],
ctaLabel: "Попробовать Pro",
ctaHref: "#",
popular: true,
variant: "featured" as const,
},
{
name: "Enterprise",
price: "custom",
description: "Для крупного бизнеса",
features: [
{ text: "Неограниченные участники", included: true },
{ text: "Неограниченные проекты", included: true },
{ text: "Кастомная аналитика", included: true },
{ text: "Выделенный менеджер", included: true },
{ text: "Все интеграции + API", included: true },
{ text: "24/7 поддержка", included: true },
{ text: "Кастомные роли и права", included: true },
],
ctaLabel: "Связаться с нами",
ctaHref: "#",
},
];
/**
* Pricing Section - секция с тарифами
*/
export function PricingSection() {
return (
<SectionContainer id="pricing">
<SectionHeader
subtitle="Тарифы"
title="Выберите подходящий план"
description="Прозрачные цены без скрытых платежей. Отмените в любое время."
withGradient
/>
<div className="grid lg:grid-cols-3 gap-8 max-w-7xl mx-auto">
{pricingPlans.map((plan) => (
<PricingCard key={plan.name} {...plan} />
))}
</div>
<div className="mt-12 text-center">
<p className="text-sm text-muted-foreground">
Все планы включают 14-дневную бесплатную пробную версию.{" "}
<a href="#" className="text-[var(--feature-accent)] hover:underline">
Сравнить все функции
</a>
</p>
</div>
</SectionContainer>
);
}

View File

@@ -0,0 +1,105 @@
"use client";
import { SectionContainer } from "@/features/section-container";
import { SectionHeader } from "@/features/section-header";
import { TestimonialCard } from "@/features/testimonial-card";
import { LogoCloud } from "@/features/logo-cloud";
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "@/shared/ui/carousel";
const testimonials = [
{
content:
"TaskFlow полностью изменил то, как мы работаем. Теперь все задачи под контролем, и команда работает намного эффективнее.",
author: {
name: "Алексей Иванов",
role: "CTO",
company: "TechStart",
avatar: "/api/placeholder/100/100",
},
rating: 5,
},
{
content:
"Интуитивный интерфейс и мощные функции. За первую неделю наша продуктивность выросла на 40%.",
author: {
name: "Мария Петрова",
role: "Product Manager",
company: "InnovateCo",
avatar: "/api/placeholder/100/100",
},
rating: 5,
},
{
content:
"Лучший инструмент для управления проектами, который я использовал. Поддержка на высшем уровне!",
author: {
name: "Дмитрий Сидоров",
role: "Team Lead",
company: "DevStudio",
avatar: "/api/placeholder/100/100",
},
rating: 5,
},
{
content:
"Отличная альтернатива дорогим решениям. Все что нужно для команды из 20 человек.",
author: {
name: "Екатерина Волкова",
role: "Operations Director",
company: "GrowthLab",
avatar: "/api/placeholder/100/100",
},
rating: 4,
},
];
const logos = [
{ name: "Company 1", src: "/api/placeholder/150/50" },
{ name: "Company 2", src: "/api/placeholder/150/50" },
{ name: "Company 3", src: "/api/placeholder/150/50" },
{ name: "Company 4", src: "/api/placeholder/150/50" },
{ name: "Company 5", src: "/api/placeholder/150/50" },
{ name: "Company 6", src: "/api/placeholder/150/50" },
{ name: "Company 7", src: "/api/placeholder/150/50" },
{ name: "Company 8", src: "/api/placeholder/150/50" },
];
/**
* Social Proof Section - секция с отзывами и логотипами клиентов
*/
export function SocialProofSection() {
return (
<SectionContainer id="testimonials" background="muted">
<SectionHeader
subtitle="Отзывы"
title="Что говорят наши клиенты"
description="Тысячи команд по всему миру доверяют TaskFlow"
withGradient
/>
<Carousel className="w-full max-w-5xl mx-auto mb-16">
<CarouselContent>
{testimonials.map((testimonial, index) => (
<CarouselItem key={index} className="md:basis-1/2 lg:basis-1/3">
<div className="p-1">
<TestimonialCard {...testimonial} />
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
<div>
<p className="text-center text-sm text-muted-foreground mb-8">
Нам доверяют лучшие компании
</p>
<LogoCloud logos={logos} variant="grid" />
</div>
</SectionContainer>
);
}

View File

@@ -0,0 +1,47 @@
"use client";
import { SectionContainer } from "@/features/section-container";
import { StatCard } from "@/features/stat-card";
import { Users, TrendingUp, Star, Puzzle } from "lucide-react";
const stats = [
{
value: "10000+",
label: "Активных пользователей",
icon: Users,
},
{
value: "99.9%",
label: "Uptime",
icon: TrendingUp,
trend: { value: 12, direction: "up" as const },
},
{
value: "4.9",
label: "Средняя оценка",
icon: Star,
},
{
value: "50+",
label: "Интеграций",
icon: Puzzle,
},
];
/**
* Stats Section - секция с цифрами/достижениями
*/
export function StatsSection() {
return (
<SectionContainer id="stats" background="muted">
<div className="grid grid-cols-2 lg:grid-cols-4 gap-8 lg:gap-12">
{stats.map((stat) => (
<StatCard key={stat.label} {...stat} animated />
))}
</div>
</SectionContainer>
);
}

View File

@@ -0,0 +1,73 @@
"use client";
import { SectionContainer } from "@/features/section-container";
import { SectionHeader } from "@/features/section-header";
import { TeamMemberCard } from "@/features/team-member-card";
const team = [
{
name: "Иван Петров",
role: "CEO & Founder",
bio: "10+ лет опыта в разработке SaaS продуктов",
image: "/api/placeholder/400/400",
socials: [
{ platform: "linkedin" as const, url: "#" },
{ platform: "twitter" as const, url: "#" },
],
},
{
name: "Анна Смирнова",
role: "CTO",
bio: "Архитектор enterprise-решений с опытом в Google",
image: "/api/placeholder/400/400",
socials: [
{ platform: "github" as const, url: "#" },
{ platform: "linkedin" as const, url: "#" },
],
},
{
name: "Михаил Козлов",
role: "Head of Product",
bio: "Создал продукты, используемые миллионами пользователей",
image: "/api/placeholder/400/400",
socials: [
{ platform: "linkedin" as const, url: "#" },
{ platform: "twitter" as const, url: "#" },
],
},
{
name: "Елена Новикова",
role: "Head of Design",
bio: "Award-winning UX/UI дизайнер с 8-летним опытом",
image: "/api/placeholder/400/400",
socials: [
{ platform: "twitter" as const, url: "#" },
{ platform: "linkedin" as const, url: "#" },
],
},
];
/**
* Team Section - секция с командой
*/
export function TeamSection() {
return (
<SectionContainer id="team">
<SectionHeader
subtitle="Команда"
title="Познакомьтесь с нашей командой"
description="Профессионалы, которые создают TaskFlow"
withGradient
/>
<div className="grid sm:grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-8">
{team.map((member) => (
<TeamMemberCard key={member.name} {...member} />
))}
</div>
</SectionContainer>
);
}