[feat] landing: 콘솔형 히어로·price-sparkline·데모 미디어(mp4/jpg) 세트 추가, phone 데모(how-it-works) 수정
This commit is contained in:
parent
9ccf42cf6b
commit
3e5f8c6cd4
51
landing/app/components/sections/hero-console.tsx
Normal file
51
landing/app/components/sections/hero-console.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { motion } from "motion/react"
|
||||||
|
import { ArrowDown, ArrowRight } from "lucide-react"
|
||||||
|
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
|
||||||
|
/** 히어로 변형 — 실시간 협상 콘솔 시즐 영상을 전면에 세운 풀와이드 히어로. */
|
||||||
|
export function HeroConsole() {
|
||||||
|
return (
|
||||||
|
<section className="relative min-h-screen bg-surface-neu text-ink flex flex-col justify-center pt-32 pb-20 overflow-hidden">
|
||||||
|
<div className="mesh-bg absolute top-[-260px] left-[-160px] opacity-40 pointer-events-none" />
|
||||||
|
|
||||||
|
<div className="max-w-6xl mx-auto px-6 w-full relative z-10">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 28, scale: 0.98 }}
|
||||||
|
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||||
|
transition={{ duration: 0.8, delay: 0.1 }}
|
||||||
|
className="rounded-[28px] overflow-hidden border border-line-strong shadow-[0_30px_80px_rgba(20,25,45,0.12)] bg-white"
|
||||||
|
>
|
||||||
|
<video
|
||||||
|
src="/gifs/hero_console.mp4"
|
||||||
|
poster="/gifs/hero_console.jpg"
|
||||||
|
autoPlay
|
||||||
|
muted
|
||||||
|
loop
|
||||||
|
playsInline
|
||||||
|
className="w-full h-auto block"
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.8, delay: 0.35 }}
|
||||||
|
className="flex flex-col sm:flex-row justify-center gap-5 pt-10"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
href="#contact-section"
|
||||||
|
className="w-full sm:w-auto group shadow-[0_8px_24px_rgba(49,130,246,0.15)] hover:scale-[1.02] active:scale-[0.98]"
|
||||||
|
>
|
||||||
|
<span>도입 문의 상담 받기</span>
|
||||||
|
<ArrowRight className="w-5 h-5 transition-transform group-hover:translate-x-1" />
|
||||||
|
</Button>
|
||||||
|
<Button href="#how-it-works" variant="glass" className="w-full sm:w-auto gap-1.5">
|
||||||
|
<span>작동 방식 보기</span>
|
||||||
|
<ArrowDown className="w-4 h-4 text-ink-soft" />
|
||||||
|
</Button>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -221,6 +221,8 @@ const DEMO_TABS: DemoTab[] = [
|
|||||||
checks: ["1:1 프라이빗 대화형 역경매 포털 제공", "불필요한 실랑이를 예방하여 파트너십 보호"],
|
checks: ["1:1 프라이빗 대화형 역경매 포털 제공", "불필요한 실랑이를 예방하여 파트너십 보호"],
|
||||||
mockup: "phone",
|
mockup: "phone",
|
||||||
gif: "/gifs/negotiation.gif",
|
gif: "/gifs/negotiation.gif",
|
||||||
|
video: "/gifs/negotiation.mp4",
|
||||||
|
poster: "/gifs/negotiation.jpg",
|
||||||
gifAlt: "AI 모바일 자동 협상 시연",
|
gifAlt: "AI 모바일 자동 협상 시연",
|
||||||
fallback: {
|
fallback: {
|
||||||
icon: Smartphone,
|
icon: Smartphone,
|
||||||
|
|||||||
58
landing/app/components/ui/price-sparkline.tsx
Normal file
58
landing/app/components/ui/price-sparkline.tsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
type PriceSparklineProps = {
|
||||||
|
/** 스텝별 가격 (시간순) */
|
||||||
|
prices: number[]
|
||||||
|
/** 점선 기준선으로 표시할 목표가 */
|
||||||
|
targetPrice: number
|
||||||
|
/** 그려질 비율 0~1 — 진행도에 맞춰 계단이 드러난다 */
|
||||||
|
progress: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 계단식 가격 하락 라인 + 목표가 점선. 진행률만큼 클립으로 드러나는 미니 차트. */
|
||||||
|
function PriceSparkline({ prices, targetPrice, progress }: PriceSparklineProps) {
|
||||||
|
const W = 100
|
||||||
|
const H = 44
|
||||||
|
// 위아래 여백을 둔 가격 범위 매핑
|
||||||
|
const hi = Math.max(...prices, targetPrice)
|
||||||
|
const lo = Math.min(...prices, targetPrice)
|
||||||
|
const pad = (hi - lo) * 0.08 || 1
|
||||||
|
const MAX = hi + pad
|
||||||
|
const MIN = lo - pad
|
||||||
|
const y = (price: number) => ((MAX - price) / (MAX - MIN)) * H
|
||||||
|
|
||||||
|
const stepX = (i: number) => (i / (prices.length - 1)) * W
|
||||||
|
|
||||||
|
// step-after 계단 경로
|
||||||
|
let d = `M 0 ${y(prices[0]).toFixed(1)}`
|
||||||
|
for (let i = 1; i < prices.length; i++) {
|
||||||
|
d += ` L ${stepX(i).toFixed(1)} ${y(prices[i - 1]).toFixed(1)} L ${stepX(i).toFixed(1)} ${y(prices[i]).toFixed(1)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" className="w-full h-16 overflow-visible" aria-hidden>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="price-spark-clip">
|
||||||
|
<rect x="0" y="-4" width={Math.max(0, Math.min(progress, 1)) * W} height={H + 8} style={{ transition: "width 0.5s ease-out" }} />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
{/* 목표가 기준선 */}
|
||||||
|
<g className="text-primary/40">
|
||||||
|
<line
|
||||||
|
x1="0"
|
||||||
|
y1={y(targetPrice)}
|
||||||
|
x2={W}
|
||||||
|
y2={y(targetPrice)}
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="1"
|
||||||
|
strokeDasharray="4 4"
|
||||||
|
vectorEffect="non-scaling-stroke"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
{/* 가격 하락 계단 — 진행률만큼 클립으로 드러남 */}
|
||||||
|
<g clipPath="url(#price-spark-clip)" className="text-primary">
|
||||||
|
<path d={d} fill="none" stroke="currentColor" strokeWidth="2.5" vectorEffect="non-scaling-stroke" strokeLinejoin="round" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { PriceSparkline }
|
||||||
BIN
landing/public/gifs/hero_console.jpg
Normal file
BIN
landing/public/gifs/hero_console.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
BIN
landing/public/gifs/hero_console.mp4
Normal file
BIN
landing/public/gifs/hero_console.mp4
Normal file
Binary file not shown.
BIN
landing/public/gifs/negotiation.jpg
Normal file
BIN
landing/public/gifs/negotiation.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
BIN
landing/public/gifs/negotiation.mp4
Normal file
BIN
landing/public/gifs/negotiation.mp4
Normal file
Binary file not shown.
BIN
landing/public/gifs/negotiation_annotated.jpg
Normal file
BIN
landing/public/gifs/negotiation_annotated.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
BIN
landing/public/gifs/negotiation_annotated.mp4
Normal file
BIN
landing/public/gifs/negotiation_annotated.mp4
Normal file
Binary file not shown.
BIN
landing/public/gifs/negotiation_result.jpg
Normal file
BIN
landing/public/gifs/negotiation_result.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
landing/public/gifs/negotiation_result.mp4
Normal file
BIN
landing/public/gifs/negotiation_result.mp4
Normal file
Binary file not shown.
BIN
landing/public/gifs/quote_generation.jpg
Normal file
BIN
landing/public/gifs/quote_generation.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
BIN
landing/public/gifs/quote_generation.mp4
Normal file
BIN
landing/public/gifs/quote_generation.mp4
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user