353 lines
16 KiB
TypeScript
353 lines
16 KiB
TypeScript
/**
|
|
* @file app/(home)/page.tsx
|
|
* @description 서비스 메인 랜딩 페이지(Server Component)
|
|
*/
|
|
|
|
import Link from "next/link";
|
|
import type { LucideIcon } from "lucide-react";
|
|
import {
|
|
Activity,
|
|
ArrowRight,
|
|
ShieldCheck,
|
|
Sparkles,
|
|
TrendingUp,
|
|
Zap,
|
|
} from "lucide-react";
|
|
import { Header } from "@/features/layout/components/header";
|
|
import { AUTH_ROUTES } from "@/features/auth/constants";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import ShaderBackground from "@/components/ui/shader-background";
|
|
import { createClient } from "@/utils/supabase/server";
|
|
|
|
interface ValuePoint {
|
|
value: string;
|
|
label: string;
|
|
detail: string;
|
|
}
|
|
|
|
interface FeatureItem {
|
|
icon: LucideIcon;
|
|
eyebrow: string;
|
|
title: string;
|
|
description: string;
|
|
}
|
|
|
|
interface StartStep {
|
|
step: string;
|
|
title: string;
|
|
description: string;
|
|
}
|
|
|
|
const VALUE_POINTS: ValuePoint[] = [
|
|
{
|
|
value: "3분",
|
|
label: "초기 세팅 시간",
|
|
detail: "복잡한 설정 대신 질문 기반으로 빠르게 시작합니다.",
|
|
},
|
|
{
|
|
value: "24시간",
|
|
label: "실시간 시장 관제",
|
|
detail: "자리 비운 시간에도 규칙 기반으로 자동 대응합니다.",
|
|
},
|
|
{
|
|
value: "0원",
|
|
label: "가입 시작 비용",
|
|
detail: "부담 없이 계정 생성 후 내 투자 스타일부터 점검합니다.",
|
|
},
|
|
];
|
|
|
|
const FEATURE_ITEMS: FeatureItem[] = [
|
|
{
|
|
icon: ShieldCheck,
|
|
eyebrow: "Risk Guard",
|
|
title: "손실 방어를 먼저 설계합니다",
|
|
description:
|
|
"진입보다 중요한 것은 방어입니다. 손절 기준과 노출 한도를 먼저 세워 감정 개입을 줄입니다.",
|
|
},
|
|
{
|
|
icon: TrendingUp,
|
|
eyebrow: "Data Momentum",
|
|
title: "데이터로 타점을 좁힙니다",
|
|
description:
|
|
"실시간 데이터 흐름을 읽어 조건이 맞을 때만 실행합니다. 초보도 납득 가능한 근거를 확인할 수 있습니다.",
|
|
},
|
|
{
|
|
icon: Zap,
|
|
eyebrow: "Auto Execution",
|
|
title: "기회가 오면 즉시 자동 실행합니다",
|
|
description:
|
|
"규칙이 충족되면 지연 없이 주문이 실행됩니다. 잠자는 시간과 업무 시간에도 전략은 멈추지 않습니다.",
|
|
},
|
|
];
|
|
|
|
const START_STEPS: StartStep[] = [
|
|
{
|
|
step: "STEP 01",
|
|
title: "계정 연결",
|
|
description: "안내에 따라 거래 계정을 안전하게 연결합니다.",
|
|
},
|
|
{
|
|
step: "STEP 02",
|
|
title: "성향 선택",
|
|
description: "공격형·균형형·안정형 중 내 스타일을 고릅니다.",
|
|
},
|
|
{
|
|
step: "STEP 03",
|
|
title: "자동 실행 시작",
|
|
description: "선택한 전략으로 실시간 관제를 바로 시작합니다.",
|
|
},
|
|
];
|
|
|
|
/**
|
|
* 홈 메인 랜딩 페이지
|
|
* @returns 랜딩 UI
|
|
* @see features/layout/components/header.tsx blendWithBackground 모드 헤더를 함께 사용
|
|
*/
|
|
export default async function HomePage() {
|
|
// [로그인 상태 조회] 사용자 유무에 따라 CTA 링크를 분기합니다.
|
|
const supabase = await createClient();
|
|
const {
|
|
data: { user },
|
|
} = await supabase.auth.getUser();
|
|
|
|
// [CTA 분기] 로그인 여부에 따라 같은 위치에서 다른 행동으로 자연스럽게 전환합니다.
|
|
const primaryCtaHref = user ? AUTH_ROUTES.DASHBOARD : AUTH_ROUTES.SIGNUP;
|
|
const primaryCtaLabel = user ? "대시보드로 전략 실행하기" : "무료로 시작하고 첫 전략 받기";
|
|
const secondaryCtaHref = user ? AUTH_ROUTES.DASHBOARD : AUTH_ROUTES.LOGIN;
|
|
const secondaryCtaLabel = user ? "실시간 상태 확인하기" : "기존 계정으로 로그인";
|
|
|
|
return (
|
|
<div className="flex min-h-screen flex-col overflow-x-hidden bg-transparent">
|
|
<Header user={user} showDashboardLink={true} blendWithBackground={true} />
|
|
|
|
<main className="relative isolate flex-1 overflow-hidden pt-16">
|
|
{/* ========== SHADER BACKGROUND SECTION ========== */}
|
|
<ShaderBackground opacity={1} className="-z-20" />
|
|
<div aria-hidden="true" className="pointer-events-none absolute inset-0 -z-10 bg-black/45" />
|
|
<div
|
|
aria-hidden="true"
|
|
className="pointer-events-none absolute -left-40 top-40 -z-10 h-96 w-96 rounded-full bg-brand-500/20 blur-3xl"
|
|
/>
|
|
<div
|
|
aria-hidden="true"
|
|
className="pointer-events-none absolute -right-24 top-72 -z-10 h-[26rem] w-[26rem] rounded-full bg-brand-300/20 blur-3xl"
|
|
/>
|
|
|
|
{/* ========== HERO SECTION ========== */}
|
|
<section className="container mx-auto max-w-7xl px-4 pb-14 pt-14 md:pt-24">
|
|
<div className="grid gap-8 lg:grid-cols-12 lg:gap-10">
|
|
<div className="lg:col-span-7">
|
|
<span className="inline-flex animate-in fade-in-0 items-center gap-2 rounded-full border border-brand-400/40 bg-brand-500/15 px-4 py-1.5 text-xs font-semibold tracking-wide text-brand-100 backdrop-blur-md duration-700">
|
|
<Sparkles className="h-3.5 w-3.5" />
|
|
초보 투자자를 위한 전략 자동매매 파트너
|
|
</span>
|
|
|
|
<h1 className="mt-5 animate-in slide-in-from-bottom-4 text-4xl font-black tracking-tight text-white [text-shadow:0_6px_40px_rgba(0,0,0,0.55)] duration-700 md:text-6xl">
|
|
감이 아닌 전략으로,
|
|
<br />
|
|
<span className="bg-linear-to-r from-brand-100 via-brand-300 to-brand-500 bg-clip-text text-transparent">
|
|
내 계좌의 성장 루틴을 만드세요
|
|
</span>
|
|
</h1>
|
|
|
|
<p className="mt-5 max-w-2xl animate-in slide-in-from-bottom-4 text-sm leading-relaxed text-white/80 duration-700 md:text-lg">
|
|
주린이는 보호와 성장의 균형을 먼저 설계합니다.
|
|
<br />
|
|
손실 방어 규칙, 데이터 신호, 자동 실행을 하나의 흐름으로 묶어 초보의 첫 수익 루틴을 만듭니다.
|
|
</p>
|
|
|
|
<div className="mt-8 flex animate-in flex-col gap-3 duration-700 sm:flex-row">
|
|
<Button
|
|
asChild
|
|
size="lg"
|
|
className="group h-12 rounded-full bg-linear-to-r from-brand-500 via-brand-400 to-brand-600 px-8 text-base font-semibold text-white shadow-2xl shadow-brand-800/45 [background-size:200%_200%] animate-gradient-x hover:brightness-110"
|
|
>
|
|
<Link href={primaryCtaHref}>
|
|
{primaryCtaLabel}
|
|
<ArrowRight className="h-4 w-4 transition-transform group-hover:translate-x-0.5" />
|
|
</Link>
|
|
</Button>
|
|
<Button
|
|
asChild
|
|
variant="outline"
|
|
size="lg"
|
|
className="h-12 rounded-full border-white/35 bg-black/30 px-8 text-base text-white backdrop-blur-md hover:bg-white/10 hover:text-white"
|
|
>
|
|
<Link href={secondaryCtaHref}>{secondaryCtaLabel}</Link>
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="mt-4 flex flex-wrap gap-3 text-xs text-white/70">
|
|
<span className="rounded-full border border-white/20 bg-white/5 px-3 py-1 backdrop-blur-sm">
|
|
가입 3분
|
|
</span>
|
|
<span className="rounded-full border border-white/20 bg-white/5 px-3 py-1 backdrop-blur-sm">
|
|
카드 등록 없음
|
|
</span>
|
|
<span className="rounded-full border border-white/20 bg-white/5 px-3 py-1 backdrop-blur-sm">
|
|
언제든 전략 변경 가능
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="relative lg:col-span-5">
|
|
<div className="absolute -inset-px rounded-3xl bg-linear-to-br from-brand-300/50 via-brand-600/0 to-brand-600/60 blur-lg" />
|
|
<div className="relative overflow-hidden rounded-3xl border border-white/15 bg-black/35 p-6 shadow-[0_30px_90px_-45px_rgba(0,0,0,0.85)] backdrop-blur-2xl">
|
|
<div className="flex items-center justify-between border-b border-white/10 pb-4">
|
|
<div>
|
|
<p className="text-xs font-semibold tracking-wide text-brand-200">LIVE STRATEGY STATUS</p>
|
|
<p className="mt-1 text-lg font-semibold text-white">실시간 자동매매 관제</p>
|
|
</div>
|
|
<span className="inline-flex items-center gap-1 rounded-full bg-brand-500/25 px-3 py-1 text-xs font-semibold text-brand-100">
|
|
<Activity className="h-3.5 w-3.5" />
|
|
안정 운영중
|
|
</span>
|
|
</div>
|
|
|
|
{/* [신뢰 포인트] UI 안에서 가치 제안을 한눈에 보여 주기 위해 핵심 상태를 카드형으로 배치합니다. */}
|
|
<div className="mt-5 grid gap-3">
|
|
<div className="rounded-2xl border border-white/10 bg-white/5 px-4 py-3">
|
|
<p className="text-xs text-white/65">리스크 룰 적용</p>
|
|
<p className="mt-1 text-sm font-semibold text-white">손실 제한 + 분할 대응 활성화</p>
|
|
</div>
|
|
<div className="rounded-2xl border border-white/10 bg-white/5 px-4 py-3">
|
|
<p className="text-xs text-white/65">데이터 신호 감시</p>
|
|
<p className="mt-1 text-sm font-semibold text-white">시장 흐름 조건 충족 시 자동 진입</p>
|
|
</div>
|
|
<div className="rounded-2xl border border-white/10 bg-white/5 px-4 py-3">
|
|
<p className="text-xs text-white/65">실행 상태</p>
|
|
<p className="mt-1 text-sm font-semibold text-white">체결 지연 최소화, 규칙 기반 지속 운영</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-5 flex items-center gap-2 text-xs text-brand-100/90">
|
|
<span className="inline-block h-2 w-2 rounded-full bg-brand-300" />
|
|
당신의 전략은 설정한 원칙 안에서만 실행됩니다.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-10 grid gap-4 md:grid-cols-3">
|
|
{VALUE_POINTS.map((point) => (
|
|
<div
|
|
key={point.label}
|
|
className="rounded-2xl border border-white/10 bg-white/5 p-6 backdrop-blur-md transition-colors hover:bg-white/10"
|
|
>
|
|
<p className="text-2xl font-black text-brand-100">{point.value}</p>
|
|
<p className="mt-2 text-sm font-semibold text-white">{point.label}</p>
|
|
<p className="mt-2 text-xs leading-relaxed text-white/70">{point.detail}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</section>
|
|
|
|
{/* ========== FEATURE SECTION ========== */}
|
|
<section className="container mx-auto max-w-7xl px-4 pb-16 md:pb-24">
|
|
<div className="mx-auto max-w-3xl text-center">
|
|
<p className="text-xs font-semibold tracking-widest text-brand-200">WHY JURINI</p>
|
|
<h2 className="mt-3 text-3xl font-black tracking-tight text-white md:text-4xl">
|
|
초보에게 필요한 건 복잡함이 아니라
|
|
<br />
|
|
<span className="text-brand-200">기준이 분명한 자동매매</span>입니다
|
|
</h2>
|
|
</div>
|
|
|
|
<div className="mt-8 grid gap-6 md:grid-cols-3">
|
|
{FEATURE_ITEMS.map((feature) => {
|
|
const FeatureIcon = feature.icon;
|
|
|
|
return (
|
|
<Card
|
|
key={feature.title}
|
|
className="group border-white/10 bg-black/25 text-white shadow-none backdrop-blur-md transition-all hover:-translate-y-1 hover:border-brand-400/40 hover:bg-black/35"
|
|
>
|
|
<CardHeader>
|
|
<div className="mb-2 inline-flex h-12 w-12 items-center justify-center rounded-2xl bg-brand-500/20 text-brand-200 transition-transform group-hover:scale-110">
|
|
<FeatureIcon className="h-6 w-6" />
|
|
</div>
|
|
<p className="text-xs font-semibold tracking-wide text-brand-200">{feature.eyebrow}</p>
|
|
<CardTitle className="text-xl leading-snug text-white">{feature.title}</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="text-sm leading-relaxed text-white/75">
|
|
{feature.description}
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
})}
|
|
</div>
|
|
</section>
|
|
|
|
{/* ========== START STEP SECTION ========== */}
|
|
<section className="container mx-auto max-w-7xl px-4 pb-16">
|
|
<div className="rounded-3xl border border-white/10 bg-white/5 p-6 backdrop-blur-xl md:p-10">
|
|
<div className="flex flex-col justify-between gap-8 md:flex-row md:items-end">
|
|
<div>
|
|
<p className="text-xs font-semibold tracking-widest text-brand-200">GET STARTED</p>
|
|
<h2 className="mt-3 text-3xl font-black tracking-tight text-white md:text-4xl">
|
|
가입부터 자동 실행까지
|
|
<br />
|
|
<span className="text-brand-200">딱 3단계면 충분합니다</span>
|
|
</h2>
|
|
</div>
|
|
<p className="max-w-sm text-sm leading-relaxed text-white/70">
|
|
어려운 설정 화면 대신, 따라 하기 쉬운 단계로 바로 시작할 수 있게 구성했습니다.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="mt-8 grid gap-4 md:grid-cols-3">
|
|
{START_STEPS.map((item) => (
|
|
<div key={item.step} className="rounded-2xl border border-white/10 bg-black/30 p-5">
|
|
<p className="text-xs font-semibold tracking-wide text-brand-200">{item.step}</p>
|
|
<p className="mt-2 text-lg font-semibold text-white">{item.title}</p>
|
|
<p className="mt-2 text-sm leading-relaxed text-white/70">{item.description}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* ========== CTA SECTION ========== */}
|
|
<section className="container mx-auto max-w-7xl px-4 pb-20">
|
|
<div className="relative overflow-hidden rounded-3xl border border-brand-300/30 bg-linear-to-r from-brand-600/30 via-brand-500/20 to-brand-700/30 p-8 backdrop-blur-xl md:p-12">
|
|
<div
|
|
aria-hidden="true"
|
|
className="absolute -right-20 -top-20 h-72 w-72 rounded-full bg-brand-200/25 blur-3xl"
|
|
/>
|
|
<div
|
|
aria-hidden="true"
|
|
className="absolute -bottom-24 -left-16 h-72 w-72 rounded-full bg-brand-700/30 blur-3xl"
|
|
/>
|
|
|
|
<div className="relative z-10 flex flex-col items-center justify-between gap-8 text-center md:flex-row md:text-left">
|
|
<div>
|
|
<p className="text-sm font-semibold text-brand-100">수익의 시작은 빠를수록 좋습니다</p>
|
|
<h2 className="mt-2 text-3xl font-black tracking-tight text-white md:text-4xl">
|
|
지금 가입하고,
|
|
<br />
|
|
내 전략을 오늘부터 자동 실행하세요
|
|
</h2>
|
|
<p className="mt-3 text-sm text-white/75 md:text-base">
|
|
주린이가 첫 설정부터 실행까지 함께 안내합니다.
|
|
</p>
|
|
</div>
|
|
|
|
<Button
|
|
asChild
|
|
size="lg"
|
|
className="group h-14 rounded-full bg-white px-9 text-lg font-bold text-brand-700 shadow-xl shadow-black/35 hover:bg-white/90"
|
|
>
|
|
<Link href={primaryCtaHref}>
|
|
지금 시작하기
|
|
<ArrowRight className="ml-2 h-5 w-5" />
|
|
</Link>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|