Initial commit: party-mix-app with prefetch cache, audio preload optimizations
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
164
apps/web/src/app/page.tsx
Normal file
164
apps/web/src/app/page.tsx
Normal file
@@ -0,0 +1,164 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
const EQ_BARS = [
|
||||
{ h: 35, d: 0 },
|
||||
{ h: 72, d: 0.12 },
|
||||
{ h: 50, d: 0.23 },
|
||||
{ h: 90, d: 0.06 },
|
||||
{ h: 55, d: 0.17 },
|
||||
{ h: 82, d: 0.28 },
|
||||
{ h: 44, d: 0.09 },
|
||||
{ h: 96, d: 0.20 },
|
||||
{ h: 60, d: 0.14 },
|
||||
{ h: 76, d: 0.03 },
|
||||
{ h: 40, d: 0.25 },
|
||||
{ h: 85, d: 0.18 },
|
||||
{ h: 52, d: 0.07 },
|
||||
{ h: 67, d: 0.30 },
|
||||
{ h: 30, d: 0.11 },
|
||||
{ h: 78, d: 0.22 },
|
||||
{ h: 48, d: 0.16 },
|
||||
{ h: 88, d: 0.04 },
|
||||
{ h: 62, d: 0.26 },
|
||||
{ h: 38, d: 0.19 },
|
||||
]
|
||||
|
||||
const FEATURES = [
|
||||
{
|
||||
icon: '🎵',
|
||||
title: 'Совместная очередь',
|
||||
desc: 'Каждый гость добавляет свои треки — никто не обделён эфиром',
|
||||
},
|
||||
{
|
||||
icon: '🎲',
|
||||
title: 'Умный шаффл',
|
||||
desc: 'По очереди или случайно — два режима миксовки плейлиста',
|
||||
},
|
||||
{
|
||||
icon: '🔍',
|
||||
title: 'Поиск версий',
|
||||
desc: 'Автоматически находит нужную версию трека',
|
||||
},
|
||||
{
|
||||
icon: '📋',
|
||||
title: 'Плейлисты',
|
||||
desc: 'Сохраняй сеты для разных компаний и запускай одним кликом',
|
||||
},
|
||||
]
|
||||
|
||||
export default function LandingPage() {
|
||||
return (
|
||||
<div className="max-w-app mx-auto min-h-[calc(100vh-40px)] flex flex-col">
|
||||
|
||||
{/* ── Nav ── */}
|
||||
<nav className="flex items-center justify-between py-3 mb-2">
|
||||
<div className="flex items-center gap-2.5">
|
||||
<div className="w-8 h-8 rounded-[9px] bg-accent flex items-center justify-center shrink-0">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M9 18V5l12-2v13" stroke="#0a0a0f" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||
<circle cx="6" cy="18" r="3" fill="#0a0a0f" />
|
||||
<circle cx="18" cy="16" r="3" fill="#0a0a0f" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="font-display font-extrabold text-lg tracking-tight">
|
||||
Party<span className="text-accent">Mix</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Link
|
||||
href="/login"
|
||||
className="text-[13px] font-sans text-muted hover:text-app-text transition-colors duration-150 px-2 py-1"
|
||||
>
|
||||
Войти
|
||||
</Link>
|
||||
<Link
|
||||
href="/register"
|
||||
className="text-[13px] font-display font-semibold px-4 py-1.5 bg-surface border border-white/[0.07] rounded-xl text-app-text hover:border-white/20 hover:bg-surface2 transition-all duration-150"
|
||||
>
|
||||
Регистрация
|
||||
</Link>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* ── Hero ── */}
|
||||
<section className="flex-1 flex flex-col items-center justify-center text-center py-12 relative">
|
||||
|
||||
{/* Ambient glow behind EQ */}
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[500px] h-[200px] pointer-events-none" aria-hidden="true">
|
||||
<div className="absolute inset-0 bg-accent/[0.04] rounded-full blur-3xl" />
|
||||
</div>
|
||||
|
||||
{/* EQ visualization */}
|
||||
<div className="relative flex items-end gap-[4px] mb-8 h-20" aria-hidden="true">
|
||||
{EQ_BARS.map(({ h, d }, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="eq-bar"
|
||||
style={{
|
||||
height: `${h}%`,
|
||||
animationDelay: `${d}s`,
|
||||
animationDuration: `${0.6 + d * 0.8}s`,
|
||||
width: '3px',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Title */}
|
||||
<h1 className="font-display font-extrabold leading-none tracking-tight mb-5 text-[72px] sm:text-[104px]">
|
||||
Party<span className="text-accent">Mix</span>
|
||||
</h1>
|
||||
|
||||
{/* Tagline */}
|
||||
<p className="font-sans text-base sm:text-lg text-muted max-w-[320px] mb-10 leading-relaxed">
|
||||
Совместные плейлисты для вечеринок.
|
||||
<br />
|
||||
Каждый гость — часть музыки.
|
||||
</p>
|
||||
|
||||
{/* CTA buttons */}
|
||||
<div className="flex items-center gap-3 flex-wrap justify-center">
|
||||
<Link
|
||||
href="/app"
|
||||
className="px-8 py-3 bg-accent text-bg font-display font-bold text-sm rounded-xl hover:brightness-110 active:scale-[0.97] transition-all duration-150 shadow-[0_0_24px_rgba(200,255,0,0.25)]"
|
||||
>
|
||||
Начать вечеринку →
|
||||
</Link>
|
||||
<Link
|
||||
href="/login"
|
||||
className="px-8 py-3 bg-surface border border-white/[0.07] text-app-text font-sans text-sm rounded-xl hover:bg-surface2 hover:border-white/20 active:scale-[0.97] transition-all duration-150"
|
||||
>
|
||||
Войти
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── Divider ── */}
|
||||
<div className="border-t border-white/[0.05] mb-8" />
|
||||
|
||||
{/* ── Features ── */}
|
||||
<section className="pb-10">
|
||||
<p className="text-[11px] font-display font-semibold tracking-[1.5px] uppercase text-muted mb-4">
|
||||
Возможности
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
{FEATURES.map(({ icon, title, desc }) => (
|
||||
<div
|
||||
key={title}
|
||||
className="group bg-surface border border-white/[0.07] rounded-app p-4 hover:bg-surface2 hover:border-white/[0.12] transition-all duration-200"
|
||||
>
|
||||
<span className="text-lg mb-2.5 block">{icon}</span>
|
||||
<h3 className="font-display font-bold text-[13px] mb-1 text-app-text">{title}</h3>
|
||||
<p className="text-[12px] text-muted font-sans leading-relaxed">{desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── Footer ── */}
|
||||
<footer className="pb-4 text-center">
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user