diff --git a/app/services/website/page.tsx b/app/services/website/page.tsx index 6dea74c..68e879c 100644 --- a/app/services/website/page.tsx +++ b/app/services/website/page.tsx @@ -1,7 +1,7 @@ 'use client'; import Link from 'next/link'; -import { useState } from 'react'; +import { useState, useEffect, useRef } from 'react'; const samples = [ { @@ -74,6 +74,16 @@ const samples = [ tags: ['라이프', '독서', '기록'], icon: '◻', }, + { + type: 'shopping', + title: '개인 쇼핑몰', + subtitle: 'MELLOW STUDIO', + desc: '감각적인 브랜드 스토리텔링과 미니멀 레이아웃으로 완성한 패션·라이프스타일 쇼핑몰', + gradient: 'linear-gradient(135deg, #2A2018 0%, #4A3C2C 50%, #7A6A52 100%)', + accent: '#C4A882', + tags: ['쇼핑몰', '패션', '라이프'], + icon: '◇', + }, ]; const processSteps = [ @@ -127,193 +137,349 @@ const faqs = [ }, ]; +function useReveal() { + const ref = useRef(null); + useEffect(() => { + const el = ref.current; + if (!el) return; + const scroller = (document.querySelector('.main-content') as HTMLElement | null) ?? document.documentElement; + const obs = new IntersectionObserver( + ([entry]) => { if (entry.isIntersecting) { el.classList.add('ws-visible'); obs.disconnect(); } }, + { threshold: 0.1, root: scroller === document.documentElement ? null : scroller } + ); + obs.observe(el); + return () => obs.disconnect(); + }, []); + return ref; +} + export default function WebsiteServicePage() { const [openFaq, setOpenFaq] = useState(null); + const [showTop, setShowTop] = useState(false); + + useEffect(() => { + const scroller = (document.querySelector('.main-content') as HTMLElement | null) ?? document.documentElement; + const onScroll = () => setShowTop(scroller.scrollTop > 400); + scroller.addEventListener('scroll', onScroll, { passive: true }); + return () => scroller.removeEventListener('scroll', onScroll); + }, []); + + const samplesRef = useReveal(); + const processRef = useReveal(); + const pricingRef = useReveal(); + const faqRef = useReveal(); + const ctaRef = useReveal(); return ( -
- +
+