diff --git a/app/freelance/layout.tsx b/app/freelance/layout.tsx deleted file mode 100644 index becf6bd..0000000 --- a/app/freelance/layout.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import type { Metadata } from 'next'; - -export const metadata: Metadata = { - title: '외주 개발 의뢰', - description: - '계약서 먼저, 납기 지키고, 소스코드 100% 인도. 47건 납품 완료. 현직 실무 엔지니어에게 외주 개발을 맡겨보세요. 납기 지연 시 하루 10만 원 패널티.', - keywords: [ - '외주 개발', - '프리랜서 개발자', - '웹 개발 외주', - '앱 개발 외주', - 'RPA 개발', - '업무 자동화 외주', - '소프트웨어 개발', - ], - openGraph: { - title: '외주 개발 의뢰 | 쟁승메이드', - description: - '47건 납품 완료. 계약서 먼저, 납기 패널티, 소스코드 100% 인도. 연락 두절 없는 개발자.', - url: 'https://jaengseung-made.com/freelance', - }, - robots: { index: false, follow: false }, -}; - -export default function FreelanceLayout({ children }: { children: React.ReactNode }) { - return children; -} diff --git a/app/freelance/page.tsx b/app/freelance/page.tsx deleted file mode 100644 index 2d76179..0000000 --- a/app/freelance/page.tsx +++ /dev/null @@ -1,711 +0,0 @@ -'use client'; - -import { useState, useEffect, useRef } from 'react'; -import ContactForm from '../components/ContactForm'; - -/* ─── Data ─── */ -const portfolio = [ - { - title: '기업 브랜드 홈페이지', - category: '웹사이트 제작 · Next.js', - desc: '제조업체의 영업용 기업 소개 사이트. 서비스·연혁·팀 소개·문의 폼 포함. 모바일 반응형 및 SEO 최적화까지 포함하여 납품.', - result: '납품 후 B2B 영업 미팅 시 "홈페이지 보고 연락했다" 비율 증가', - tags: ['Next.js', 'Tailwind CSS', 'Vercel', 'SEO'], - status: '납품 완료', - statusType: 'done', - priceRange: '50~200만원', - accentColor: 'text-indigo-400', - accentBg: 'bg-[#0d0a2e]', - borderAccent: 'border-indigo-400/20', - }, - { - title: 'Gmail 자동화 RPA', - category: 'RPA · 업무 자동화', - desc: '거래처 이메일 수신 시 자동 분류, 답장 초안 작성, 담당자 알림 전송하는 Gmail 자동화 시스템.', - result: '이메일 처리 시간 일 2시간 → 10분 (의뢰인 직접 확인)', - tags: ['Python', 'Gmail API', 'Google Apps Script'], - status: '납품 완료', - statusType: 'done', - priceRange: '30~150만원', - accentColor: 'text-red-400', - accentBg: 'bg-[#200a0a]', - borderAccent: 'border-red-400/20', - }, - { - title: '쇼핑몰 가격 모니터링 봇', - category: '웹 스크래핑 · 알림 자동화', - desc: '경쟁사 쇼핑몰의 특정 상품 가격을 매일 모니터링하여 변동 시 텔레그램으로 즉시 알림.', - result: '경쟁사 10곳 · 상품 50개 매일 자동 추적, 수동 확인 0분', - tags: ['Python', 'Selenium', 'Telegram Bot'], - status: '납품 완료', - statusType: 'done', - priceRange: '30~150만원', - accentColor: 'text-violet-400', - accentBg: 'bg-[#0d0a2e]', - borderAccent: 'border-violet-400/20', - }, - { - title: '영업 일보 자동화 시스템', - category: '엑셀 자동화 · 보고서 생성', - desc: '영업 데이터 엑셀 파일을 자동으로 집계하여 일별/주별/월별 영업 일보 PDF를 생성하고 이메일 발송.', - result: '보고서 작성 3시간 → 5분, 매일 09:00 자동 발송', - tags: ['Python', 'OpenPyXL', 'ReportLab'], - status: '납품 완료', - statusType: 'done', - priceRange: '30~150만원', - accentColor: 'text-cyan-400', - accentBg: 'bg-[#012030]', - borderAccent: 'border-cyan-400/20', - }, - { - title: '부동산 공시지가 수집 시스템', - category: '공공 데이터 · API 연동', - desc: '국토교통부 공공 API를 통해 특정 지역 공시지가를 주기적으로 수집·저장하고 변동 알림 제공.', - result: '전국 3개 지역 공시지가 주 1회 자동 수집·변동 알림', - tags: ['Python', '공공데이터 API', 'PostgreSQL', 'Telegram'], - status: '납품 완료', - statusType: 'done', - priceRange: '30~150만원', - accentColor: 'text-blue-400', - accentBg: 'bg-[#04102b]', - borderAccent: 'border-blue-400/20', - }, -]; - -const testimonials = [ - { - name: '이서준', - role: '온라인 쇼핑몰 운영자', - project: '경쟁사 가격 모니터링 봇', - content: '경쟁사 10곳 가격을 매일 수동으로 확인했는데 이제 텔레그램으로 자동 알림 받습니다. 납기도 정확히 지켜주셨고, 완료 후에도 작은 수정 요청에 빠르게 응답해주셔서 믿음이 갔습니다.', - result: '가격 모니터링 시간 → 0분/일', - accentColor: 'bg-emerald-500', - borderColor: 'border-emerald-200', - tagColor: 'text-emerald-700 bg-emerald-50 border-emerald-200', - }, - { - name: '박하은', - role: '스타트업 운영팀장', - project: 'Excel 보고서 자동화 시스템', - content: '매주 월요일 아침 2시간씩 쓰던 Excel 집계 작업을 자동화했습니다. 처음엔 반신반의했는데 계약서부터 작성해주셔서 진짜 전문가구나 싶었고, 결과물도 기대 이상이었습니다.', - result: '주간 보고 작업 2시간 → 5분', - accentColor: 'bg-blue-500', - borderColor: 'border-blue-200', - tagColor: 'text-blue-700 bg-blue-50 border-blue-200', - }, - { - name: '김도윤', - role: '프리랜서 디자이너', - project: '포트폴리오 웹사이트 제작', - content: '이전에 다른 개발자한테 맡겼다가 중간에 연락이 끊겼던 경험이 있어서 많이 걱정했는데, 주 1회 진행 보고를 꼬박꼬박 해주시고 최종 소스코드까지 전달해주셔서 정말 만족했습니다.', - result: '2주 납품 약속 정확히 이행', - accentColor: 'bg-violet-500', - borderColor: 'border-violet-200', - tagColor: 'text-violet-700 bg-violet-50 border-violet-200', - }, -]; - -const process = [ - { - num: '01', - title: '무료 상담', - desc: '전화 또는 이메일로 요구사항 파악 (30분 이내)', - sub: '비용 없음 · 부담 없음', - icon: ( - - - - ), - }, - { - num: '02', - title: '견적 제안', - desc: '개발 범위, 일정, 비용 상세 견적서 제공', - sub: '1~3일 이내 발송', - icon: ( - - - - ), - }, - { - num: '03', - title: '계약 체결', - desc: '계약서 작성 및 계약금(30%) 입금 후 개발 시작', - sub: '계약서 포함 · 안전 거래', - icon: ( - - - - ), - }, - { - num: '04', - title: '개발 진행', - desc: '주 1회 이상 진행 상황 공유 및 중간 검수', - sub: '투명한 진행 보고', - icon: ( - - - - ), - highlight: true, - }, - { - num: '05', - title: '최종 납품', - desc: '완성본 인도 + 사용 교육 + 소스코드 전달', - sub: '소스코드 전체 제공', - icon: ( - - - - ), - }, - { - num: '06', - title: 'AS 지원', - desc: '1개월 무상 기술 지원 및 평생 유지보수 가능', - sub: '1개월 무상 + 평생 AS', - icon: ( - - - - ), - }, -]; - -const guarantees = [ - { - label: '계약서 필수', - detail: '구두 약속 없음 — 착수 전 계약서 발송', - icon: ( - - - - ), - accentText: 'text-sky-400', - accentBorder: 'border-sky-400/20', - }, - { - label: '납기 지연 패널티', - detail: '하루 지연 = 10만원 감면 — 그래서 안 늦습니다', - icon: ( - - - - ), - accentText: 'text-amber-400', - accentBorder: 'border-amber-400/20', - }, - { - label: '소스코드 100% 인도', - detail: '납품 후 전체 소스코드 + 배포 가이드 제공', - icon: ( - - - - ), - accentText: 'text-emerald-400', - accentBorder: 'border-emerald-400/20', - }, - { - label: '1개월 무상 AS', - detail: '납품 후 한 달 — 버그·수정 무상 대응', - icon: ( - - - - ), - accentText: 'text-violet-400', - accentBorder: 'border-violet-400/20', - }, - { - label: '실시간 진행 현황', - detail: '마이페이지에서 7단계 진행 상황 직접 확인', - icon: ( - - - - ), - accentText: 'text-cyan-400', - accentBorder: 'border-cyan-400/20', - }, -]; - -/* ─── Scroll Reveal ─── */ -function useScrollReveal() { - const ref = useRef(null); - useEffect(() => { - const el = ref.current; - if (!el) return; - const observer = new IntersectionObserver( - (entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - entry.target.classList.add('is-visible'); - observer.unobserve(entry.target); - } - }); - }, - { threshold: 0.1, rootMargin: '0px 0px -40px 0px' } - ); - el.querySelectorAll('.reveal').forEach((child) => observer.observe(child)); - return () => observer.disconnect(); - }, []); - return ref; -} - -/* ─── Main Page ─── */ -export default function FreelancePage() { - const [_contactPreset] = useState(''); - const containerRef = useScrollReveal(); - - return ( -
- - - {/* ─── Hero ─── */} -
-
-
-
- - 현재 프로젝트 접수 가능 -
-

- 연락 두절? 그런 거 없습니다.
- 납기 지키고, 끝까지 책임집니다 -

-

- 개발자에게 맡겼다가 연락 두절된 경험 있으신가요?
- 계약서 작성, 중간 보고, 소스코드 인도까지 — 단계마다 증거를 남깁니다. -

-
- - {/* Developer tag */} -
-
- 박 -
-
-
쟁토리 (박재오)
-
실무 엔지니어 · Python / Java / Next.js
-
-
- {['Python', 'Java', 'Next.js', 'Docker'].map(t => ( - {t} - ))} -
-
- - {/* 보증 카드 4개 */} -
- {guarantees.map((g) => ( -
-
{g.icon}
-
{g.label}
-
{g.detail}
-
- ))} -
-
-
- - {/* ─── 포트폴리오 ─── */} -
-
-
-

PORTFOLIO

-

직접 개발한 프로젝트

-

실제 운영 중인 서비스와 납품 완료 프로젝트입니다

-
- -
- {portfolio.map((item) => ( -
- {/* card header */} -
-
-
-
{item.category}
-

{item.title}

-
- {item.statusType === 'live' ? ( -
- - 운영 중 -
- ) : ( -
- - - - 납품 완료 -
- )} -
-
- - {/* card body */} -
-

{item.desc}

- {item.result && ( -
- - - - {item.result} -
- )} -
- {item.tags.map((tag) => ( - - {tag} - - ))} -
- -
-
- ))} -
- - {/* 추가 문구 */} -
-

- 위 프로젝트 외에도 다양한 프로젝트 경험이 있습니다 ·{' '} - 포트폴리오 전체 요청 -

-
-
-
- - {/* ─── 고객 후기 ─── */} -
-
-
-

REVIEWS

-

실제 의뢰인 후기

-

숫자보다 실제 말이 더 정직합니다

-
- -
- {testimonials.map((t) => ( -
- {/* 별점 */} -
- {[1,2,3,4,5].map((n) => ( - - - - ))} -
- - {/* 후기 내용 */} -

- “{t.content}” -

- - {/* 결과 뱃지 */} -
- ✓ {t.result} -
- - {/* 의뢰인 */} -
-
- {t.name[0]} -
-
-
{t.name}
-
{t.role} · {t.project}
-
-
-
- ))} -
- -

- * 의뢰인 동의 하에 게시된 후기입니다. 전체 대화 내역 공개 요청 시 제공 가능합니다. -

- -
- - 무료 상담 시작하기 - -

24시간 내 답변 · 상담은 무료입니다

-
-
-
- - {/* ─── 진행 프로세스 ─── */} -
-
-
-

PROCESS

-

진행 프로세스

-

투명하고 체계적인 6단계로 진행됩니다

-
- - {/* Vertical timeline */} -
- {/* connecting line */} -
- -
- {process.map((p) => ( -
- {/* step circle */} -
- {p.icon} -
- - {/* content */} -
-
-
-
- STEP {p.num} - {p.highlight && ( - 현재 진행 - )} -
-

{p.title}

-

{p.desc}

-
-
- {p.sub} -
-
-
-
- ))} -
-
-
-
- - {/* ─── 기술 스택 & 신뢰 ─── */} -
-
- - {/* Tech Stack */} -
-
-
-

개발 가능 기술 스택

-
-
- {[ - { label: 'Backend', techs: ['Python', 'Java', 'Spring Boot', 'FastAPI', 'Node.js'] }, - { label: 'Frontend', techs: ['Next.js', 'React', 'TypeScript', 'Tailwind CSS'] }, - { label: 'Database', techs: ['PostgreSQL', 'MySQL', 'Redis', 'SQLite'] }, - { label: 'Infra / API', techs: ['Docker', 'AWS', 'Telegram API', '공공 API'] }, - ].map((group) => ( -
-
{group.label}
-
- {group.techs.map((t) => ( - - {t} - - ))} -
-
- ))} -
-
- - {/* 신뢰 포인트 */} -
-
-
-

신뢰할 수 있는 이유

-
-
    - {[ - { - title: '지금 URL로 직접 확인', - desc: 'jaengseung-made.com — 로또 분석, 주식 자동매매 지금도 운영 중', - icon: ( - - - - ), - }, - { - title: '계약서 먼저, 개발 나중', - desc: '구두 약속 없음 — 견적서·계약서 발송 후 착수', - icon: ( - - - - ), - }, - { - title: '납품 전 전액 환불 보장', - desc: '마음에 안 드시면 이유 불문 전액 환불', - icon: ( - - - - ), - }, - { - title: '소스코드 100% 인도', - desc: '완성 후 전체 소스코드 + 배포 가이드 제공', - icon: ( - - - - ), - }, - { - title: '납기 지연 시 패널티', - desc: '하루 늦을 때마다 10만원 감면 — 그래서 안 늦습니다', - icon: ( - - - - ), - }, - ].map((item) => ( -
  • - {item.icon} -
    -
    {item.title}
    -
    {item.desc}
    -
    -
  • - ))} -
-
-
-
- - {/* ─── 문의 폼 ─── */} -
-
-
-

CONTACT

-

프로젝트 문의

-

개발사 연락 두절로 손해 본 경험 있으신가요? 여기선 계약서부터 시작합니다.

-
- -
- {/* 왼쪽: 간단 안내 */} -
-
-

문의 전 체크리스트

-
    - {[ - '어떤 업무를 자동화/개발하고 싶은지', - '현재 사용 중인 시스템 (엑셀, ERP 등)', - '희망하는 완성 일정', - '예산 범위 (대략적으로도 OK)', - ].map((item, i) => ( -
  • - {i + 1} - {item} -
  • - ))} -
-
- - - -
-
24h
-
이내 답변 보장
-
영업일 기준 · 주말 포함
-
-
- - {/* 오른쪽: 폼 */} -
- -
-
-
-
-
- ); -} diff --git a/app/saju/components/SajuForm.tsx b/app/saju/components/SajuForm.tsx deleted file mode 100644 index 3313da9..0000000 --- a/app/saju/components/SajuForm.tsx +++ /dev/null @@ -1,220 +0,0 @@ -'use client'; - -import { useState } from 'react'; -import { useRouter } from 'next/navigation'; -import { lunarToSolar } from '@/lib/lunar-utils'; - -export default function SajuForm() { - const router = useRouter(); - const [year, setYear] = useState(''); - const [month, setMonth] = useState(''); - const [day, setDay] = useState(''); - const [hour, setHour] = useState(''); - const [calendarType, setCalendarType] = useState<'solar' | 'lunar'>('solar'); - const [gender, setGender] = useState<'male' | 'female'>('male'); - const [isLeapMonth, setIsLeapMonth] = useState(false); - - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - - if (!year || !month || !day) { - alert('생년월일을 모두 입력해주세요.'); - return; - } - - let finalYear = year; - let finalMonth = month; - let finalDay = day; - - // 음력인 경우 양력으로 변환 - if (calendarType === 'lunar') { - const solar = lunarToSolar( - parseInt(year), - parseInt(month), - parseInt(day), - isLeapMonth - ); - finalYear = solar.year.toString(); - finalMonth = solar.month.toString(); - finalDay = solar.day.toString(); - } - - // URL 파라미터로 전달 - const params = new URLSearchParams({ - year: finalYear, - month: finalMonth, - day: finalDay, - gender, - calendarType, - originalYear: year, - originalMonth: month, - originalDay: day, - }); - - if (hour) { - params.append('hour', hour); - } - - if (calendarType === 'lunar') { - params.append('isLeapMonth', isLeapMonth.toString()); - } - - router.push(`/saju/result?${params.toString()}`); - }; - - return ( -
- {/* 생년월일 */} -
- -
- setYear(e.target.value)} - required - /> - setMonth(e.target.value)} - required - /> - setDay(e.target.value)} - required - /> -
-
- - {/* 태어난 시간 */} -
- - -
- - {/* 양력/음력 선택 */} -
- -
- - -
- {calendarType === 'lunar' && ( -
- -
- )} -
- - {/* 성별 선택 */} -
- -
- - -
-
- - {/* 제출 버튼 */} - - -

- * 태어난 시간을 정확히 아시면 더 정확한 사주를 확인할 수 있습니다. -

-
- ); -} diff --git a/app/saju/input/page.tsx b/app/saju/input/page.tsx deleted file mode 100644 index 20742c5..0000000 --- a/app/saju/input/page.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import SajuForm from '../components/SajuForm'; - -export default function SajuInputPage() { - return ( -
- {/* Hero */} -
- -
-
- - AI 사주 분석 · 생년월일 입력 -
-

- 생년월일을 입력해주세요 -

-

- 정확한 생년월일과 태어난 시간을 입력하면
- 더 정밀한 사주팔자를 계산할 수 있습니다. -

-
-
- - {/* Form 영역 */} -
-
-
-
-

기본 정보 입력

-
- -
- -

- 입력하신 정보는 사주 계산에만 사용되며 별도로 저장되지 않습니다. -

-
-
- ); -} diff --git a/app/saju/layout.tsx b/app/saju/layout.tsx deleted file mode 100644 index 8b55313..0000000 --- a/app/saju/layout.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import type { Metadata } from 'next'; - -export const metadata: Metadata = { - title: 'AI 사주 분석', - description: - '생년월일시를 입력하면 Gemini AI가 사주팔자를 분석합니다. 일간·오행·대운·세운 기반 12개 항목 상세 해석. 재물운·애정운·직업·건강 포함.', - keywords: [ - 'AI 사주', - '사주풀이', - '사주팔자', - '사주 분석', - '오행 분석', - '대운', - '세운', - '사주 운세', - ], - openGraph: { - title: 'AI 사주 분석 | 쟁승메이드', - description: - 'Gemini AI 기반 사주팔자 분석. 일간·오행·대운·세운·재물운·애정운 12개 항목 해석.', - url: 'https://jaengseung-made.com/saju', - }, -}; - -export default function SajuLayout({ children }: { children: React.ReactNode }) { - return children; -} diff --git a/app/saju/page.tsx b/app/saju/page.tsx deleted file mode 100644 index c4a686b..0000000 --- a/app/saju/page.tsx +++ /dev/null @@ -1,334 +0,0 @@ -'use client'; - -import { useEffect, useState } from 'react'; -import Link from 'next/link'; -import PaymentButton from '@/app/components/PaymentButton'; -import { createClient } from '@/lib/supabase/client'; - -const faqItems = [ - { - q: '사주팔자란 무엇인가요?', - a: '사주팔자(四柱八字)는 태어난 년·월·일·시의 네 기둥(四柱)에 각각 천간과 지지 두 글자씩 총 여덟 글자(八字)로 이루어진 동양의 전통 운명 분석 체계입니다.', - }, - { - q: 'AI 해석은 어떻게 동작하나요?', - a: '전통 명리학 계산 로직(오행, 신강/신약, 용신/희신 등)으로 산출된 데이터를 Gemini AI에 전달하여 12개 항목의 상세 해석을 생성합니다. 현재 기본 원국 분석과 AI 상세 해석 모두 무료로 제공됩니다.', - }, - { - q: '태어난 시간을 모르면 어떻게 하나요?', - a: '시간을 모르더라도 년·월·일 세 기둥(三柱)만으로 사주를 계산할 수 있습니다. 다만 시주가 빠지면 세부 분석 정확도가 다소 낮아집니다.', - }, - { - q: '음력으로 입력할 수 있나요?', - a: '네, 양력과 음력 모두 지원합니다. 음력을 선택하면 내부적으로 양력으로 변환하여 정확한 사주를 계산합니다. 윤달도 별도 선택이 가능합니다.', - }, -]; - -interface SajuRecord { - id: number; - created_at: string; - saju_data: { - birth_year: number; - birth_month: number; - birth_day: number; - birth_hour?: number; - gender: string; - }; - interpretation: string | null; - is_paid: boolean; -} - -function buildResultUrl(rec: SajuRecord) { - const { birth_year, birth_month, birth_day, birth_hour, gender } = rec.saju_data; - if (!birth_year || !birth_month || !birth_day) return '/saju/input'; - let url = `/saju/result?year=${birth_year}&month=${birth_month}&day=${birth_day}&gender=${gender}&calendarType=solar`; - if (birth_hour != null) url += `&hour=${birth_hour}`; - return url; -} - -export default function SajuPage() { - const supabase = createClient(); - const [paidRecords, setPaidRecords] = useState([]); - const [hasPaid, setHasPaid] = useState(false); - const [authChecked, setAuthChecked] = useState(false); - - useEffect(() => { - async function fetchRecords() { - const { data: { user } } = await supabase.auth.getUser(); - if (!user) { setAuthChecked(true); return; } - - const { data: records } = await supabase - .from('saju_records') - .select('*') - .eq('user_id', user.id) - .eq('is_paid', true) - .order('created_at', { ascending: false }) - .limit(2); - - if (records && records.length > 0) { - setPaidRecords(records); - setHasPaid(true); - } - setAuthChecked(true); - } - fetchRecords(); - }, []); - - return ( -
- {/* ─── Hero ─── */} -
- -
-
- - 전통 명리학 × AI 해석 · 무료 -
-

- AI가 분석하는
- 사주팔자 -

-

- 수천 년의 동양 명리학과 최신 AI 기술의 만남.
- 태어난 순간의 우주적 에너지를 12가지 항목으로 해석해드립니다. -

- - {/* 이전 기록 있으면 분기 버튼, 없으면 단일 CTA */} - {authChecked && hasPaid ? ( -
- - - - - 새로 보기 - - - - - - 이전 내역 다시 보기 - -
- ) : ( - - - - - 지금 바로 시작하기 - - )} -
-
- -
-
- - {/* ─── 이전 기록 섹션 (구매한 유저만) ─── */} - {hasPaid && paidRecords.length > 0 && ( -
-
-

MY RECORDS

-

이전 AI 사주 기록

-

결제한 사주 기록을 다시 확인하세요

-
-
- {paidRecords.map((rec) => ( -
-
-
-
- {new Date(rec.created_at).toLocaleDateString('ko-KR', { year: 'numeric', month: 'long', day: 'numeric' })} -
-
- {rec.saju_data.birth_year ?? '?'}년{' '} - {rec.saju_data.birth_month ?? '?'}월{' '} - {rec.saju_data.birth_day ?? '?'}일생 -
-
- {rec.saju_data.gender === 'male' ? '남성' : '여성'} - {rec.saju_data.birth_hour != null ? ` · ${rec.saju_data.birth_hour}시생` : ''} -
-
- - AI 해석 완료 - -
- {rec.interpretation && ( -

- {rec.interpretation.replace(/[#*]/g, '').substring(0, 80)}... -

- )} - - 다시 보기 → - -
- ))} -
-
- )} - - {/* ─── 바로 시작하기 CTA ─── */} -
-

지금 무료로 시작하세요

-

회원가입 없이, 생년월일만 입력하면 바로 확인 가능합니다

- - 사주 입력하러 가기 → - -
- - {/* ─── 무료 vs 유료 비교표 ─── */} -
-
-

PRICING

-

무엇을 분석해드리나요

-

기본 원국은 무료, AI 상세 해석은 1,000원

-
- -
- {/* 무료 */} -
-
-
- - - -
-
-
FREE
-
무료 기본 분석
-
-
-
    - {[ - '사주팔자 원국 (년·월·일·시주)', - '천간·지지·지장간 표', - '십성 및 십이운성', - '오행 분포 차트', - '지지 상호작용 (합·충·형)', - '일간 분석 요약', - ].map((item) => ( -
  • -
    -
    -
    - {item} -
  • - ))} -
-
-
무료
-
회원가입 불필요
- - 무료로 시작하기 - -
-
- - {/* AI 해석 (현재 무료) */} -
-
- 1,000원 -
-
-
- - - -
-
-
AI PREMIUM
-
AI 상세 해석
-
-
-
    - {[ - '무료 기본 분석 전체 포함', - '신강/신약 정밀 판단', - '용신·희신·기신 추정', - '대운 (10년 주기) 분석', - '올해 세운 흐름', - 'Gemini 2.5 Pro AI 12가지 상세 해석', - ].map((item) => ( -
  • -
    -
    -
    - {item} -
  • - ))} -
-
-
- 1,000원 - / 1회 -
-
로그인 후 결제 · 12가지 항목 AI 해석
- - 사주 분석 시작하기 → - -
-
-
-
- - {/* ─── FAQ ─── */} -
-
-

FAQ

-

자주 묻는 질문

-
-
- {faqItems.map((item, i) => ( -
-
-
- Q -
-
-

{item.q}

-

{item.a}

-
-
-
- ))} -
-
- -
-
-
- ); -} diff --git a/app/saju/result/SajuAISection.tsx b/app/saju/result/SajuAISection.tsx deleted file mode 100644 index 4581af3..0000000 --- a/app/saju/result/SajuAISection.tsx +++ /dev/null @@ -1,443 +0,0 @@ -'use client'; - -import { useState, useEffect, useRef } from 'react'; -import ReactMarkdown from 'react-markdown'; -import remarkGfm from 'remark-gfm'; -import PaymentButton from '@/app/components/PaymentButton'; - -interface BirthKey { - birth_year: number; - birth_month: number; - birth_day: number; - birth_hour?: number; - gender: string; -} - -interface SajuAISectionProps { - hasPaid: boolean; - savedInterpretation: string | null; - sajuData: object; - daeun: object | null; - daeunList: object[]; - gender: string; - birthKey: BirthKey; - currentUrl: string; - engineData?: { - interactions?: any[]; - shinsal?: any[]; - gongmang?: any; - hiddenStems?: any[]; - }; -} - -// ── 섹션별 메타 (아이콘·색상) ────────────────────────────────────────── -const SECTION_META: { - icon: string; - gradient: string; - border: string; - badge: string; - badgeText: string; -}[] = [ - { icon: '🌟', gradient: 'from-violet-500 to-purple-600', border: 'border-violet-100', badge: 'bg-violet-50 border-violet-200 text-violet-700', badgeText: '기질' }, - { icon: '⚖️', gradient: 'from-emerald-500 to-teal-600', border: 'border-emerald-100', badge: 'bg-emerald-50 border-emerald-200 text-emerald-700', badgeText: '오행' }, - { icon: '🔗', gradient: 'from-blue-500 to-indigo-600', border: 'border-blue-100', badge: 'bg-blue-50 border-blue-200 text-blue-700', badgeText: '지지' }, - { icon: '✨', gradient: 'from-amber-500 to-orange-500', border: 'border-amber-100', badge: 'bg-amber-50 border-amber-200 text-amber-700', badgeText: '신살' }, - { icon: '💰', gradient: 'from-yellow-500 to-amber-600', border: 'border-yellow-100', badge: 'bg-yellow-50 border-yellow-200 text-yellow-700', badgeText: '재물' }, - { icon: '🎯', gradient: 'from-rose-500 to-pink-600', border: 'border-rose-100', badge: 'bg-rose-50 border-rose-200 text-rose-700', badgeText: '직업' }, - { icon: '💕', gradient: 'from-pink-500 to-rose-500', border: 'border-pink-100', badge: 'bg-pink-50 border-pink-200 text-pink-700', badgeText: '애정' }, - { icon: '🌿', gradient: 'from-green-500 to-emerald-600', border: 'border-green-100', badge: 'bg-green-50 border-green-200 text-green-700', badgeText: '건강' }, - { icon: '🗺️', gradient: 'from-cyan-500 to-blue-600', border: 'border-cyan-100', badge: 'bg-cyan-50 border-cyan-200 text-cyan-700', badgeText: '대운' }, - { icon: '📅', gradient: 'from-indigo-500 to-violet-600', border: 'border-indigo-100', badge: 'bg-indigo-50 border-indigo-200 text-indigo-700', badgeText: '세운' }, - { icon: '🏆', gradient: 'from-amber-400 to-yellow-500', border: 'border-amber-100', badge: 'bg-amber-50 border-amber-200 text-amber-700', badgeText: '황금기' }, - { icon: '💌', gradient: 'from-slate-600 to-slate-800', border: 'border-slate-100', badge: 'bg-slate-50 border-slate-200 text-slate-700', badgeText: '종합' }, -]; - -// ── 마크다운 → 섹션 파싱 ────────────────────────────────────────────── -interface ParsedSection { - number: number; - title: string; - content: string; -} - -function parseInterpretation(text: string): ParsedSection[] { - // "## 숫자. 제목" 패턴으로 분리 - const parts = text.split(/\n(?=##\s+\d+[\.\s])/).filter(Boolean); - const sections: ParsedSection[] = []; - - for (const part of parts) { - const lines = part.trim().split('\n'); - const headerLine = lines[0] ?? ''; - const match = headerLine.match(/^##\s+(\d+)[.\s]\s*(.+)$/); - if (match) { - sections.push({ - number: parseInt(match[1], 10), - title: match[2].trim(), - content: lines.slice(1).join('\n').trim(), - }); - } - } - - // 파싱 실패 시 전체를 하나의 섹션으로 - if (sections.length === 0 && text.trim()) { - sections.push({ number: 0, title: 'AI 해석', content: text.trim() }); - } - - return sections; -} - -// ── 섹션 카드 컴포넌트 ──────────────────────────────────────────────── -function SectionCard({ section, meta, isOpen, onToggle }: { - section: ParsedSection; - meta: typeof SECTION_META[0]; - isOpen: boolean; - onToggle: () => void; -}) { - return ( -
- {/* 헤더 */} - - - {/* 내용 (아코디언) */} - {isOpen && ( -
-
- {meta.icon} -
-
-

{children}

, - h2: ({ children }) =>

{children}

, - h3: ({ children }) =>

{children}

, - p: ({ children }) =>

{children}

, - strong: ({ children }) => {children}, - em: ({ children }) => {children}, - ul: ({ children }) =>
    {children}
, - ol: ({ children }) =>
    {children}
, - li: ({ children }) =>
  • {children}
  • , - blockquote: ({ children }) => ( -
    - {children} -
    - ), - hr: () =>
    , - code: ({ children }) => ( - - {children} - - ), - }} - > - {section.content} -
    -
    -
    - )} -
    - ); -} - -// mock 데이터 여부 감지 (저장된 해석이 예시 데이터인 경우 재생성 필요) -function isMockInterpretation(text: string | null): boolean { - if (!text) return false; - return ( - text.includes('API 키 문제 또는 할당량 초과') || - text.includes('GEMINI_API_KEY 환경변수를 설정') || - text.includes('예시 데이터를 보여드립니다') || - text.includes('API 설정이 필요합니다') - ); -} - -// ── 메인 컴포넌트 ────────────────────────────────────────────────────── -export default function SajuAISection({ - hasPaid, - savedInterpretation, - sajuData, - daeun, - daeunList, - gender, - birthKey, - currentUrl, - engineData, -}: SajuAISectionProps) { - // 저장된 해석이 mock 데이터면 재생성 필요 - const isMock = isMockInterpretation(savedInterpretation); - const validSaved = savedInterpretation && !isMock ? savedInterpretation : null; - - const [status, setStatus] = useState<'idle' | 'loading' | 'done' | 'error'>( - validSaved ? 'done' : 'idle' - ); - const [interpretation, setInterpretation] = useState(validSaved ?? ''); - const [openSections, setOpenSections] = useState>(new Set([0])); - const called = useRef(false); - - const sections = parseInterpretation(interpretation); - - const toggleSection = (idx: number) => { - setOpenSections(prev => { - const next = new Set(prev); - if (next.has(idx)) next.delete(idx); - else next.add(idx); - return next; - }); - }; - - const expandAll = () => setOpenSections(new Set(sections.map((_, i) => i))); - const collapseAll = () => setOpenSections(new Set()); - - // 재생성: called ref 초기화 후 다시 API 호출 - const handleRegenerate = () => { - called.current = false; - setStatus('idle'); - setInterpretation(''); - // idle → useEffect가 다시 실행되도록 상태 전환 트리거 - setTimeout(() => { - called.current = false; - setStatus('loading'); - fetch('/api/saju/analyze', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ saju: sajuData, daeun, daeunList, gender, engineData }), - }) - .then(r => r.json()) - .then(data => { - if (data.interpretation && !isMockInterpretation(data.interpretation)) { - setInterpretation(data.interpretation); - setStatus('done'); - setOpenSections(new Set([0])); - // DB에 실제 해석으로 덮어쓰기 - const { birth_year, birth_month, birth_day } = birthKey; - if (typeof birth_year === 'number' && typeof birth_month === 'number' && typeof birth_day === 'number') { - fetch('/api/saju/save-interpretation', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ interpretation: data.interpretation, birthKey }), - }).catch(() => {}); - } - } else { - setStatus('error'); - } - }) - .catch(() => setStatus('error')); - }, 0); - }; - - useEffect(() => { - if (!hasPaid || validSaved || called.current) return; - called.current = true; - setStatus('loading'); - - fetch('/api/saju/analyze', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ saju: sajuData, daeun, daeunList, gender, engineData }), - }) - .then(r => r.json()) - .then(data => { - if (data.interpretation) { - setInterpretation(data.interpretation); - setStatus('done'); - // 첫 번째 섹션 자동 열기 - setOpenSections(new Set([0])); - - const { birth_year, birth_month, birth_day } = birthKey; - if ( - typeof birth_year === 'number' && !isNaN(birth_year) && - typeof birth_month === 'number' && !isNaN(birth_month) && - typeof birth_day === 'number' && !isNaN(birth_day) - ) { - fetch('/api/saju/save-interpretation', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ interpretation: data.interpretation, birthKey }), - }).catch(() => {}); - } - } else { - setStatus('error'); - } - }) - .catch(() => setStatus('error')); - }, [hasPaid]); - - // ── 미결제 ────────────────────────────────────────────────────────── - if (!hasPaid) { - return ( -
    -
    -
    -
    - AI PREMIUM -
    -

    AI 상세 해석 (12개 항목)

    -

    - 성격, 재물운, 직업 적성, 애정운, 건강운, 대운 분석 등
    - Gemini 2.5 Pro가 생성하는 맞춤형 사주 해석을 받아보세요. -

    - - {/* 미리보기 섹션 목록 */} -
    - {SECTION_META.map((meta, i) => ( -
    - {meta.icon} - {meta.badgeText} -
    - ))} -
    - - - AI 상세 해석 받기 — 1,000원 - -

    결제 후 즉시 AI 분석 시작 · 로그인 필요

    -
    -
    - ); - } - - // ── 로딩 ────────────────────────────────────────────────────────── - if (status === 'loading') { - return ( -
    -
    -

    AI가 사주를 분석하는 중입니다...

    -

    약 20~30초 소요될 수 있습니다

    -
    - {SECTION_META.map((meta, i) => ( - - {meta.icon}{meta.badgeText} - - ))} -
    -
    - ); - } - - // ── 오류 ────────────────────────────────────────────────────────── - if (status === 'error') { - return ( -
    -

    AI 해석 생성에 실패했습니다.

    - -
    - ); - } - - // ── 해석 완료 ───────────────────────────────────────────────────── - return ( -
    - {/* 헤더 */} -
    -
    - - - -
    -
    -

    AI 상세 해석

    -

    12개 항목 · 클릭해서 펼쳐보세요

    -
    -
    - - - 결제 완료 - -
    -
    - - {/* 섹션 컨트롤 + 목록 */} -
    - {/* 전체 펼치기/접기 */} - {sections.length > 1 && ( -
    - - 총 {sections.length}개 항목 - -
    - - -
    -
    - )} - - {/* 섹션 카드 목록 */} -
    - {sections.map((section, idx) => { - const metaIdx = section.number > 0 ? Math.min(section.number - 1, SECTION_META.length - 1) : idx % SECTION_META.length; - const meta = SECTION_META[metaIdx]; - return ( - toggleSection(idx)} - /> - ); - })} -
    - - {/* 하단 안내 */} - {sections.length > 0 && ( -

    - 해석은 사주 데이터를 기반으로 AI가 생성한 내용입니다. 참고용으로 활용해주세요. -

    - )} -
    -
    - ); -} diff --git a/app/saju/result/SajuFortuneSection.tsx b/app/saju/result/SajuFortuneSection.tsx deleted file mode 100644 index 8607d95..0000000 --- a/app/saju/result/SajuFortuneSection.tsx +++ /dev/null @@ -1,323 +0,0 @@ -'use client'; - -import { useMemo } from 'react'; - -// ── 천간 / 지지 ─────────────────────────────────────────────────────── -const STEMS = ['甲','乙','丙','丁','戊','己','庚','辛','壬','癸']; -const STEMS_KR = ['갑','을','병','정','무','기','경','신','임','계']; -const BRANCHES = ['子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥']; -const BRANCHES_KR= ['자','축','인','묘','진','사','오','미','신','유','술','해']; - -const STEM_ELEM: Record = { '甲':'木','乙':'木','丙':'火','丁':'火','戊':'土','己':'土','庚':'金','辛':'金','壬':'水','癸':'水' }; -const BRANCH_ELEM: Record = { '子':'水','亥':'水','寅':'木','卯':'木','巳':'火','午':'火','申':'金','酉':'金','丑':'土','辰':'土','未':'土','戌':'土' }; - -// 1900-01-01 = 甲戌 (stem=0, branch=10) — CLAUDE.md 검증 완료 -const BASE_MS = Date.UTC(1900, 0, 1); - -function getTodayPillar() { - const now = new Date(); - const todayMs = Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()); - const diff = Math.round((todayMs - BASE_MS) / 86400000); - const si = ((0 + diff) % 10 + 10) % 10; - const bi = ((10 + diff) % 12 + 12) % 12; - return { - stem: STEMS[si], stemKr: STEMS_KR[si], - branch: BRANCHES[bi], branchKr: BRANCHES_KR[bi], - stemElem: STEM_ELEM[STEMS[si]] ?? '木', - branchElem: BRANCH_ELEM[BRANCHES[bi]] ?? '水', - year: now.getFullYear(), month: now.getMonth() + 1, date: now.getDate(), - }; -} - -// ── 오행 상생·상극 ──────────────────────────────────────────────────── -const GENERATES: Record = { '木':'火','火':'土','土':'金','金':'水','水':'木' }; -const OVERCOMES: Record = { '木':'土','火':'金','土':'水','金':'木','水':'火' }; - -type Rel = 'same'|'generates'|'generated'|'overcomes'|'overcome'|'neutral'; -function getRelation(a: string, b: string): Rel { - if (a === b) return 'same'; - if (GENERATES[a] === b) return 'generates'; - if (GENERATES[b] === a) return 'generated'; - if (OVERCOMES[a] === b) return 'overcomes'; - if (OVERCOMES[b] === a) return 'overcome'; - return 'neutral'; -} - -// ── 오늘 종합 점수 (0–100) ──────────────────────────────────────────── -function calcOverallScore(stemElem: string, branchElem: string, yongShin: string, heeShin: string) { - let score = 50; - const add = (rel: Rel, weight: number) => { - if (rel === 'same') score += 25 * weight; - else if (rel === 'generates' || rel === 'generated') score += 15 * weight; - else if (rel === 'overcomes') score -= 20 * weight; - else if (rel === 'overcome') score -= 8 * weight; - }; - add(getRelation(stemElem, yongShin), 1); - add(getRelation(branchElem, yongShin), 0.8); - add(getRelation(stemElem, heeShin), 0.3); - add(getRelation(branchElem, heeShin), 0.2); - return Math.round(Math.max(10, Math.min(100, score))); -} - -type Level = 'great'|'good'|'neutral'|'caution'; -function toLevel(s: number): Level { - if (s >= 78) return 'great'; - if (s >= 58) return 'good'; - if (s >= 38) return 'neutral'; - return 'caution'; -} - -// ── 결정론적 랜덤 ──────────────────────────────────────────────────── -function seededRand(seed: number) { - let s = seed; - return () => { s = (s * 1664525 + 1013904223) & 0xffffffff; return (s >>> 0) / 0xffffffff; }; -} - -// ── 운세 항목 빌드 ──────────────────────────────────────────────────── -type Area = { icon: string; label: string; score: number; desc: string }; - -const DESCS: Record> = { - money: { - great: '재물 흐름이 활발합니다. 작은 투자나 구매 결정에 긍정적인 시기입니다.', - good: '재물 운이 순조롭습니다. 무리하지 않는 범위에서 움직이면 이익이 납니다.', - neutral: '수입·지출이 균형을 이루는 날. 큰 결정은 잠시 미루세요.', - caution: '충동 지출에 주의하세요. 중요한 금전 거래는 신중히 검토하세요.', - }, - love: { - great: '감정 교류가 잘 이루어지는 날. 마음을 전하기 좋은 타이밍입니다.', - good: '관계에 따뜻한 기운이 감돕니다. 오래 연락 못 했던 사람에게 먼저 다가가 보세요.', - neutral: '평온한 관계를 유지하는 날입니다. 억지로 변화를 만들 필요 없습니다.', - caution: '오해가 생기기 쉬운 날입니다. 중요한 대화는 감정이 차분해진 후에 하세요.', - }, - career: { - great: '능력이 잘 발휘되는 날. 중요한 프레젠테이션이나 면담에 최적입니다.', - good: '업무 효율이 올라가는 날입니다. 오늘 마무리한 과제는 좋은 결과로 이어집니다.', - neutral: '꾸준히 하던 일을 이어가는 날. 새 프로젝트보다 마무리에 집중하세요.', - caution: '실수가 생기기 쉬운 날입니다. 중요한 결재·계약은 하루 늦춰보세요.', - }, - health: { - great: '체력·집중력 모두 좋은 날. 평소보다 활동량을 늘려도 괜찮습니다.', - good: '컨디션이 안정적입니다. 가벼운 운동으로 기운을 더 끌어올리세요.', - neutral: '무리하지 않는 것이 최선. 충분한 수분과 수면을 챙겨주세요.', - caution: '피로가 쌓이기 쉬운 날입니다. 무리한 약속은 피하고 충분히 쉬세요.', - }, - social: { - great: '대인관계 운이 열린 날. 중요한 만남·협상에 유리한 시기입니다.', - good: '사교적 기운이 넘칩니다. 새 인맥을 만들거나 협업을 제안해보세요.', - neutral: '조용히 자신의 일에 집중하는 날. 복잡한 인간관계는 잠시 내려놓으세요.', - caution: '갈등이 생기기 쉬운 날입니다. 중요한 협상은 다음 기회로 미루는 것이 현명합니다.', - }, -}; - -function buildAreas( - overall: number, - yongShin: string, heeShin: string, - yearNum: number, monthNum: number, dayNum: number, -): Area[] { - const now = new Date(); - const seed = yearNum * 1_000_000 + monthNum * 10_000 + dayNum * 100 + now.getFullYear() % 100 * 10 + now.getMonth(); - const rand = seededRand(seed); - const roll = () => Math.round(Math.max(15, Math.min(98, rand() * 40 + overall - 20))); - const keys = ['money','love','career','health','social'] as const; - const icons = ['💰','💕','🎯','🌿','🤝']; - const labels = ['재물운','애정운','직업운','건강운','사회운']; - return keys.map((k, i) => { - const s = roll(); - return { icon: icons[i], label: labels[i], score: s, desc: DESCS[k][toLevel(s)] }; - }); -} - -// ── 레벨별 색상/라벨 ───────────────────────────────────────────────── -const LEVEL_META: Record = { - great: { emoji:'🌟', label:'아주 좋은 날', bar:'#f59e0b', bg:'bg-amber-50', border:'border-amber-300', text:'text-amber-800', badge:'bg-amber-100 text-amber-700 border-amber-300' }, - good: { emoji:'✨', label:'좋은 날', bar:'#22c55e', bg:'bg-emerald-50',border:'border-emerald-300',text:'text-emerald-800',badge:'bg-emerald-100 text-emerald-700 border-emerald-300' }, - neutral: { emoji:'🌤️', label:'평온한 날', bar:'#64748b', bg:'bg-slate-50', border:'border-slate-200', text:'text-slate-700', badge:'bg-slate-100 text-slate-600 border-slate-200' }, - caution: { emoji:'⚠️', label:'조심하는 날', bar:'#f97316', bg:'bg-orange-50', border:'border-orange-300',text:'text-orange-800', badge:'bg-orange-100 text-orange-700 border-orange-300' }, -}; - -const REL_DESC: (yongShin: string, yongShinKr: string) => Record = (y, yk) => ({ - same: `오늘 기운이 당신의 용신 ${y}(${yk})과 같은 오행으로 강하게 공명합니다.`, - generates: `오늘 기운이 용신 ${y}(${yk})을 생(生)해줍니다. 순조롭게 힘이 실리는 날.`, - generated: `용신 ${y}(${yk})이 오늘 기운을 생(生)해주고 있어 에너지를 베풀기 좋은 날입니다.`, - overcomes: `오늘 기운이 용신 ${y}(${yk})을 극(克)합니다. 신중하게 움직이는 것이 좋습니다.`, - overcome: `용신 ${y}(${yk})이 오늘 기운을 극(克)합니다. 주도적으로 판단하기 좋은 날.`, - neutral: `오늘 기운과 용신 ${y}(${yk})은 독립적으로 작용합니다. 차분하게 나아가세요.`, -}); - -// ── 점수 바 ────────────────────────────────────────────────────────── -function ScoreBar({ score, color }: { score: number; color: string }) { - return ( -
    -
    -
    -
    - {score} -
    - ); -} - -// ── 메인 컴포넌트 ───────────────────────────────────────────────────── -interface Props { - yongShin: string; - yongShinKr: string; - heeShin: string; - heeShinKr: string; - yearNum: number; - monthNum: number; - dayNum: number; - hasLottoSubscription: boolean; -} - -export default function SajuFortuneSection({ - yongShin, yongShinKr, heeShin, heeShinKr, - yearNum, monthNum, dayNum, - hasLottoSubscription, -}: Props) { - const today = useMemo(getTodayPillar, []); - const overall = useMemo(() => calcOverallScore(today.stemElem, today.branchElem, yongShin, heeShin), [today, yongShin, heeShin]); - const level = toLevel(overall); - const meta = LEVEL_META[level]; - const areas = useMemo(() => buildAreas(overall, yongShin, heeShin, yearNum, monthNum, dayNum), [overall, yongShin, heeShin, yearNum, monthNum, dayNum]); - const stemRel = getRelation(today.stemElem, yongShin); - const relDesc = REL_DESC(yongShin, yongShinKr)[stemRel]; - - return ( - <> - {/* ── 상단 연결 화살표 ── */} -
    -
    -
    - 사주 분석에서 이어지는 오늘의 운세 -
    -
    -
    - - {/* ── 본문 카드 ── */} -
    - {/* 헤더 */} -
    -
    -
    -
    - ☀️ -
    -
    -

    오늘의 운세

    -

    - {today.year}년 {today.month}월 {today.date}일 · 일진 {today.stem}{today.branch} ({today.stemKr}{today.branchKr}) -

    -
    -
    - - {meta.emoji} {meta.label} - -
    -
    - -
    - {/* 일진 × 용신 분석 */} -
    -
    -
    - {today.stem}{today.branch} -
    -
    -
    - 오늘 일진과 당신의 용신 {yongShin}({yongShinKr}) 분석 -
    -

    - {relDesc} -

    -
    -
    - - {/* 종합 점수 바 */} -
    - 오늘 종합 운세 -
    -
    -
    - {overall}점 -
    -
    - - {/* 5대 운세 그리드 */} -
    -

    오늘의 분야별 운세

    -
    - {areas.map((area) => { - const aLevel = toLevel(area.score); - const aMeta = LEVEL_META[aLevel]; - return ( -
    -
    - {area.icon} -
    -
    -
    - {area.label} - {aMeta.emoji} -
    - -

    {area.desc}

    -
    -
    - ); - })} -
    -
    - - {/* 면책 */} -

    - 오늘의 운세는 당신의 사주 용신({yongShinKr}·{yongShin})과 오늘 일진의 오행 상호작용을 기반으로 합니다.
    - 명리학적 참고 자료이며 결과를 보장하지 않습니다. -

    - - {/* 로또 CTA */} -
    -
    -
    -
    - 🎱 - - {level === 'great' ? '오늘 운이 아주 좋습니다! 로또도 한 번 도전해보세요.' : '사주 기반 행운 번호도 확인해보세요.'} - -
    -

    - 용신 {yongShin}({yongShinKr}) 오행이 담긴 - 사주 기반 로또 번호가 아래에 준비되어 있습니다. - {hasLottoSubscription - ? ' 구독 중이신 로또 서비스의 매주 최신 추천 번호도 함께 확인하세요.' - : ' 로또 구독 시 대운 교차 분석으로 더 정밀한 번호를 매주 받을 수 있어요.'} -

    - { - e.preventDefault(); - document.getElementById('saju-lotto-section')?.scrollIntoView({ behavior: 'smooth', block: 'start' }); - }} - className="block w-full text-center bg-gradient-to-r from-amber-500 to-amber-400 hover:from-amber-400 hover:to-amber-300 text-[#04102b] text-sm font-extrabold px-4 py-2.5 rounded-xl transition-all shadow-lg cursor-pointer" - > - 오늘의 로또 번호 추천 보기 ↓ - -
    -
    -
    -
    - - {/* 하단 연결 */} -
    -
    -
    - 🎱 오늘의 운세에서 이어지는 사주 로또 추천 -
    -
    -
    - - ); -} diff --git a/app/saju/result/page.tsx b/app/saju/result/page.tsx deleted file mode 100644 index a883f88..0000000 --- a/app/saju/result/page.tsx +++ /dev/null @@ -1,627 +0,0 @@ -import { calculateSaju } from '@/lib/saju-calculator'; -import Link from 'next/link'; -import { calculateDaeun, getCurrentDaeun, getDaeunDescription } from '@/lib/daeun-calculator'; -import { getCurrentSolarTerm, getSolarTermName, getSolarTermMonthBranch } from '@/lib/solar-terms'; -import { EARTHLY_BRANCHES_KR, FIVE_ELEMENTS_KR, FIVE_ELEMENTS } from '@/lib/saju-calculator'; -import { calculateElementScore, performFullAnalysis } from '@/lib/ai-interpretation'; -import { createClient } from '@/lib/supabase/server'; -import SajuAISection from './SajuAISection'; -import SajuFortuneSection from './SajuFortuneSection'; - -interface PageProps { - searchParams: Promise<{ - year: string; - month: string; - day: string; - hour?: string; - gender: 'male' | 'female'; - calendarType: 'solar' | 'lunar'; - originalYear?: string; - originalMonth?: string; - originalDay?: string; - isLeapMonth?: string; - }>; -} - -export default async function SajuResultPage({ searchParams }: PageProps) { - const params = await searchParams; - const { year, month, day, hour, gender, calendarType, originalYear, originalMonth, originalDay, isLeapMonth } = params; - - const yearNum = parseInt(year, 10); - const monthNum = parseInt(month, 10); - const dayNum = parseInt(day, 10); - const hourNum = hour ? parseInt(hour, 10) : null; - - if (isNaN(yearNum) || isNaN(monthNum) || isNaN(dayNum)) { - return ( -
    -
    -

    잘못된 접근입니다. 생년월일을 다시 입력해주세요.

    - 사주 입력하기 -
    -
    - ); - } - - const inputYear = originalYear ? parseInt(originalYear) : yearNum; - const inputMonth = originalMonth ? parseInt(originalMonth) : monthNum; - const inputDay = originalDay ? parseInt(originalDay) : dayNum; - const isLunar = calendarType === 'lunar'; - const isLeap = isLeapMonth === 'true'; - - // ── 사주팔자 계산 (TypeScript — lunar-javascript 기반 정밀 절기 계산) ── - const sajuData = calculateSaju(yearNum, monthNum, dayNum, hourNum, gender); - - // 추가 분석 (신강신약, 용신, 오행균형, 세운) - const analysis = performFullAnalysis(sajuData); - const elementScores = analysis.elementScores; - - // 대운 - const currentYear = new Date().getFullYear(); - const daeunList = calculateDaeun( - yearNum, monthNum, dayNum, gender, - sajuData.month.stem, sajuData.month.branch - ); - const currentDaeun = getCurrentDaeun(daeunList, currentYear); - - // 지지 상호작용 / 신살 / 공망 / 지장간 - const branchInteractions = analysis.branchInteractions; - const shinsal = analysis.shinsal; - const gongmang = analysis.gongmang; - const hiddenStems = analysis.hiddenStems; - - // ── 절기 정보 (표시용) ──────────────────────────────────────────────── - const solarTermIndex = getCurrentSolarTerm(yearNum, monthNum, dayNum); - const solarTermName = getSolarTermName(solarTermIndex); - - // ── 결제 여부 + 저장된 AI 해석 + 로또 구독 확인 ───────────────────── - let hasPaid = false; - let savedInterpretation: string | null = null; - let hasLottoSubscription = false; - try { - const supabase = await createClient(); - const { data: { user } } = await supabase.auth.getUser(); - if (user) { - // 사주 결제 확인 (anon client — 본인 orders는 RLS 허용 가정) - const { data: order } = await supabase - .from('orders').select('id') - .eq('user_id', user.id).eq('product_id', 'saju_detail').eq('status', 'paid') - .maybeSingle(); - hasPaid = !!order; - - if (hasPaid) { - // 1차: birth_hour 포함 정확한 키로 조회 - const birthKey: Record = { birth_year: yearNum, birth_month: monthNum, birth_day: dayNum, gender }; - if (hourNum !== null) birthKey.birth_hour = hourNum; - const { data: record } = await supabase - .from('saju_records').select('interpretation') - .eq('user_id', user.id).eq('is_paid', true) - .contains('saju_data', birthKey).maybeSingle(); - savedInterpretation = record?.interpretation ?? null; - - // 2차 폴백: birth_hour 없이 조회 (시간 입력 안 한 케이스 or 불일치 방지) - if (!savedInterpretation) { - const birthKeyNoHour: Record = { birth_year: yearNum, birth_month: monthNum, birth_day: dayNum, gender }; - const { data: record2 } = await supabase - .from('saju_records').select('interpretation') - .eq('user_id', user.id).eq('is_paid', true) - .contains('saju_data', birthKeyNoHour).maybeSingle(); - savedInterpretation = record2?.interpretation ?? null; - } - } - - // 로또 구독 확인 — subscriptions 테이블 (세션 클라이언트로 RLS select_own 통과) - const { data: lottoSub } = await supabase - .from('subscriptions') - .select('id') - .eq('user_id', user.id) - .eq('status', 'active') - .in('product_id', ['lotto_gold', 'lotto_platinum', 'lotto_diamond', 'lotto_annual']) - .maybeSingle(); - hasLottoSubscription = !!lottoSub; - - // subscriptions에서 못 찾으면 orders 테이블로 폴백 (구독 마이그레이션 전 데이터) - if (!hasLottoSubscription) { - const now = new Date().toISOString(); - const thirtyOneDaysAgo = new Date(Date.now() - 31 * 24 * 60 * 60 * 1000).toISOString(); - const { data: lottoOrder } = await supabase - .from('orders') - .select('id, created_at') - .eq('user_id', user.id) - .eq('status', 'paid') - .in('product_id', ['lotto_gold', 'lotto_platinum', 'lotto_diamond', 'lotto_annual']) - .gte('created_at', thirtyOneDaysAgo) - .maybeSingle(); - hasLottoSubscription = !!lottoOrder; - } - } - } catch { - // 미로그인 시 무시 - } - - // ── 오행 색상 ────────────────────────────────────────────────────────── - const elementColors: { [k: string]: string } = { - '木': 'text-green-700', '火': 'text-red-600', '土': 'text-yellow-700', - '金': 'text-amber-600', '水': 'text-blue-700', - }; - const elementBgColors: { [k: string]: string } = { - '木': 'bg-green-50 border-green-400', '火': 'bg-red-50 border-red-400', - '土': 'bg-yellow-50 border-yellow-400', '金': 'bg-amber-50 border-amber-400', - '水': 'bg-blue-50 border-blue-400', - }; - - // ── 띠 계산 ──────────────────────────────────────────────────────────── - const zodiacAnimals = ['쥐', '소', '호랑이', '토끼', '용', '뱀', '말', '양', '원숭이', '닭', '개', '돼지']; - const zodiacIdx = (yearNum - 4) % 12; - const zodiacAnimal = zodiacAnimals[zodiacIdx >= 0 ? zodiacIdx : zodiacIdx + 12]; - - const engineBadge = TS 계산; - - return ( -
    - {/* 헤더 */} -
    -
    -
    - - 사주팔자 감정서 -
    -

    사주팔자 분석 결과

    -

    전통 명리학과 AI 기술의 만남

    -
    -
    - -
    -
    - - {/* 사이드바 */} - - - {/* 메인 */} -
    - - {/* 사주팔자 표 */} -
    -

    사주팔자 (四柱八字)

    - -
    - - - - - {sajuData.hour && } - - - - - - - {/* 천간 */} - - - {sajuData.hour && ( - - )} - - - - - - {/* 지지 */} - - - {sajuData.hour && ( - - )} - - - - - - {/* 지장간 */} - - - {(() => { - const order = sajuData.hour - ? ['시주', '일주', '월주', '년주'] - : ['일주', '월주', '년주']; - return order.map((pillarName, idx) => { - const h = hiddenStems.find((hs: any) => hs.pillar === pillarName); - return ( - - ); - }); - })()} - - - {/* 십성 */} - - - {sajuData.hour && ( - - )} - - - - - - {/* 십이운성 */} - - - {sajuData.hour && ( - - )} - - - - - -
    구분시주일주월주년주
    천간 -
    {sajuData.hour.stem}
    -
    {sajuData.hour.stemKr}
    -
    -
    {sajuData.day.stem}
    -
    {sajuData.day.stemKr}
    -
    일간
    -
    -
    {sajuData.month.stem}
    -
    {sajuData.month.stemKr}
    -
    -
    {sajuData.year.stem}
    -
    {sajuData.year.stemKr}
    -
    지지 -
    {sajuData.hour.branch}
    -
    {sajuData.hour.branchKr}
    -
    -
    {sajuData.day.branch}
    -
    {sajuData.day.branchKr}
    -
    -
    {sajuData.month.branch}
    -
    {sajuData.month.branchKr}
    -
    -
    {sajuData.year.branch}
    -
    {sajuData.year.branchKr}
    -
    -
    지장간
    -
    숨은 천간
    -
    - {h && ( -
    - {h.stems.map((s: any, si: number) => ( - - {s.stemKr} - - ))} -
    - )} -
    십성 -
    {sajuData.hour.tenGod}
    -
    -
    {sajuData.day.tenGod}
    -
    -
    {sajuData.month.tenGod}
    -
    -
    {sajuData.year.tenGod}
    -
    십이운성 -
    {sajuData.hour.fortune}
    -
    -
    {sajuData.day.fortune}
    -
    -
    {sajuData.month.fortune}
    -
    -
    {sajuData.year.fortune}
    -
    -
    - - {/* 지지 상호작용 */} - {branchInteractions.length > 0 && ( -
    -

    지지 상호작용

    -
    - {branchInteractions.map((inter: any, idx: number) => { - const isPositive = inter.type.includes('합'); - const isNegative = inter.type.includes('충') || inter.type.includes('형'); - const colorClass = isPositive - ? 'bg-emerald-50 border-emerald-400 text-emerald-800' - : isNegative - ? 'bg-red-50 border-red-400 text-red-800' - : 'bg-amber-50 border-amber-400 text-amber-800'; - return ( - - {inter.type} {inter.branchesKr.join('')} - {inter.resultElement && ` → ${FIVE_ELEMENTS_KR[inter.resultElement as keyof typeof FIVE_ELEMENTS_KR]}`} - - ); - })} -
    -
    - )} - - {/* 오행 균형 */} -
    -

    오행 균형

    -
    - {Object.entries(elementScores).map(([element, score]) => ( -
    -
    {element}
    -
    - {FIVE_ELEMENTS_KR[element as keyof typeof FIVE_ELEMENTS_KR]} -
    -
    -
    -
    -
    {score}%
    -
    - ))} -
    -
    -
    - - {/* 분석 카드 그리드 */} -
    - - {/* 신강/신약 + 용신 */} -
    -

    일간 세력 분석

    -
    - - {analysis.dayMasterStrength.result} - - 점수: {analysis.dayMasterStrength.score} -
    -
      - {analysis.dayMasterStrength.reasons.map((r: string, i: number) => ( -
    • - - - {r} -
    • - ))} -
    - -
    -

    용신 / 희신 / 기신

    -
    - - 용신: {analysis.yongShin.yongShinKr} - - - 희신: {analysis.yongShin.heeShinKr} - - - 기신: {analysis.yongShin.giShinKr} - -
    -

    {analysis.yongShin.explanation}

    -
    -
    - - {/* 신살 + 공망 */} -
    -

    신살 (神煞)

    - {shinsal.length > 0 ? ( -
    - {shinsal.map((s: any, i: number) => ( -
    - - {s.name} - -
    -
    - {s.pillar} {s.branchKr} -
    -
    {s.description}
    -
    -
    - ))} -
    - ) : ( -

    특별한 신살이 발견되지 않았습니다.

    - )} - -
    -

    공망 (空亡)

    -
    - {gongmang.branchesKr.map((bk: string, i: number) => ( - - {bk} - - ))} -
    -

    {gongmang.description}

    -
    - - {/* 세운 정보 */} -
    -

    - {analysis.seun.year}년 세운 -

    -
    - - {analysis.seun.stemKr}{analysis.seun.branchKr} - - {analysis.seun.elementKr} 기운 -
    - {analysis.seun.interactions.length > 0 && ( -
    - {analysis.seun.interactions.map((si: any, i: number) => ( - - {si.type} {si.branchesKr.join('')} - - ))} -
    - )} -
    -
    -
    - - {/* AI 상세 해석 섹션 */} - {(() => { - const birthKey = { - birth_year: yearNum, birth_month: monthNum, birth_day: dayNum, gender, - ...(hourNum !== null ? { birth_hour: hourNum } : {}), - }; - const currentUrl = `/saju/result?year=${yearNum}&month=${monthNum}&day=${dayNum}${hourNum !== null ? `&hour=${hourNum}` : ''}&gender=${gender}&calendarType=${calendarType}${originalYear ? `&originalYear=${originalYear}&originalMonth=${originalMonth}&originalDay=${originalDay}` : ''}${isLeap ? '&isLeapMonth=true' : ''}`; - return ( - - ); - })()} - - {/* 오늘의 운세 (사주 결제 시 표시) */} - {hasPaid && ( - - )} - - {/* 대운 */} -
    -

    - 대운 (大運) — 10년 주기 운세 -

    - - {currentDaeun && ( -
    -

    현재 대운

    -
    -
    - {currentDaeun.stem}{currentDaeun.branch} -
    -
    - {currentDaeun.stemKr}{currentDaeun.branchKr} -
    -
    - {currentDaeun.age}세 ~ {currentDaeun.age + 9}세 ({currentDaeun.startYear} ~ {currentDaeun.endYear}년) -
    -
    -

    - {getDaeunDescription(currentDaeun, sajuData.day.stem)} -

    -
    - )} - -
    - {daeunList.map((daeun: any, index: number) => { - const isCurrent = currentDaeun && - daeun.startYear === currentDaeun.startYear && - daeun.endYear === currentDaeun.endYear; - return ( -
    -
    -
    {daeun.stem}{daeun.branch}
    -
    {daeun.stemKr}{daeun.branchKr}
    -
    {daeun.age}세 ~ {daeun.age + 9}세
    -
    {daeun.startYear} ~ {daeun.endYear}
    - {isCurrent && ( -
    - 현재 -
    - )} -
    -
    - ); - })} -
    -
    - -
    -
    -
    -
    - ); -} diff --git a/app/services/blog/layout.tsx b/app/services/blog/layout.tsx deleted file mode 100644 index 63ed6d4..0000000 --- a/app/services/blog/layout.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import type { Metadata } from 'next'; - -export const metadata: Metadata = { - title: '블로그 자동화 솔루션 팩 | 쟁승메이드', - description: - '쿠팡파트너스·네이버 애드포스트·브랜드커넥트 수익을 자동화하는 프롬프트 조합법 45종 + 구조 템플릿 PDF 80p + 샘플 글 10편. ₩29,000 한 번 결제, 평생 무료 업데이트.', - keywords: [ - '블로그 자동화', - 'AI 블로그 글쓰기', - '쿠팡파트너스 자동화', - '애드포스트 수익화', - '네이버 블로그 SEO', - 'ChatGPT 블로그', - '블로그 프롬프트', - ], - openGraph: { - title: '블로그 자동화 솔루션 팩 | 쟁승메이드', - description: - '쿠팡파트너스·애드포스트 수익을 자동화하는 프롬프트 + 템플릿 + 샘플. ₩29,000.', - url: 'https://jaengseung-made.com/services/blog', - }, -}; - -export default function BlogLayout({ children }: { children: React.ReactNode }) { - return children; -} diff --git a/app/services/blog/page.tsx b/app/services/blog/page.tsx deleted file mode 100644 index bfb70cf..0000000 --- a/app/services/blog/page.tsx +++ /dev/null @@ -1,243 +0,0 @@ -'use client'; - -import { useState } from 'react'; -import Link from 'next/link'; -import PurchaseAgreementModal from '../../components/PurchaseAgreementModal'; - -const PACK_ITEMS = [ - { - icon: '📝', - title: '프롬프트 조합법 45종', - desc: '상품리뷰 / 정보글 / 후기 / 비교 / 하우투 글별 최적 프롬프트 조합', - meta: 'PDF 80p', - }, - { - icon: '📐', - title: '블로그 글 구조 템플릿 12종', - desc: '쿠팡파트너스 · 애드포스트 클릭을 유도하는 검증된 글 구조', - meta: 'Notion 템플릿', - }, - { - icon: '💰', - title: '샘플 글 10편', - desc: '실제로 수익이 발생한 블로그 글 전문 + 해설 주석', - meta: '.docx · .md', - }, - { - icon: '🔍', - title: '네이버 SEO 체크리스트', - desc: 'C-Rank · D.I.A. 알고리즘 대응 14가지 체크 포인트', - meta: 'PDF 20p', - }, -]; - -const FAQS = [ - { - q: '초보자도 쓸 수 있나요?', - a: 'ChatGPT나 Claude 계정만 있으면 됩니다. 프롬프트를 복붙하는 것부터 시작해서 점차 응용하도록 설계했습니다.', - }, - { - q: '어떤 플랫폼에 맞나요?', - a: '네이버 블로그·티스토리·브런치 모두 대응. 쿠팡파트너스·애드포스트·브랜드커넥트 3가지 수익화 흐름을 모두 다룹니다.', - }, - { - q: '업데이트는 얼마나 자주 되나요?', - a: '월 1~2회 주요 업데이트. 구매자 전용 Notion 페이지에서 변경 이력과 최신 파일을 제공합니다. 구매 후 12개월간 무료.', - }, - { - q: '환불이 되나요?', - a: '전자상거래법상 디지털 콘텐츠는 제공 시작 후 환불이 제한됩니다. 구매 전 샘플 미리보기를 충분히 확인해주세요. 파일 손상·전달 불량은 즉시 재전달 또는 환불됩니다.', - }, -]; - -export default function BlogServicePage() { - const [agreeOpen, setAgreeOpen] = useState(false); - const [openFaq, setOpenFaq] = useState(0); - - return ( -
    - {/* HERO */} -
    -
    -

    - Blog Automation Pack -

    -

    - 매일 글쓰기 고민, -
    - AI에게 맡기세요. -

    -

    - 쿠팡파트너스 · 네이버 애드포스트 · 브랜드커넥트 수익을 -
    - 자동화하는 프롬프트 · 구조 · 샘플 세트. -

    -
    - ₩29,000 - 한 번 결제 · 12개월 무료 업데이트 -
    -
    - - - 샘플 미리보기 - -
    -
    -
    - - {/* PAIN POINTS */} -
    -
    -

    - 이런 분들을 위한 팩입니다. -

    -
    - {[ - { icon: '🕐', title: '매일 1시간+', desc: '글 소재·구성에 시간 다 쓰고 수익은 제자리' }, - { icon: '📉', title: '수익화 6개월+', desc: '블로그 키워놓고도 수익 구조가 안 잡힘' }, - { icon: '🤖', title: 'AI 글은 어색', desc: 'ChatGPT 그대로 복붙하면 바로 들통' }, - ].map((p) => ( -
    -
    {p.icon}
    -

    {p.title}

    -

    - {p.desc} -

    -
    - ))} -
    -
    -
    - - {/* PACK CONTENT */} -
    -
    -

    - Pack Contents -

    -

    - 구성품 4종 -

    -
    - {PACK_ITEMS.map((it) => ( -
    -
    {it.icon}
    -
    -
    -

    {it.title}

    - - {it.meta} - -
    -

    - {it.desc} -

    -
    -
    - ))} -
    - - {/* Sample preview */} -
    - - 샘플 미리보기 - -

    프롬프트 예시 · 상품 리뷰 글 자동 생성

    -
    {`당신은 [카테고리] 전문 블로거입니다.
    -아래 상품의 [핵심 장점 3개]와 [주의점 1개]를 기반으로
    -C-Rank 알고리즘에 최적화된 1,200자 리뷰 글을 작성하세요.
    -
    -[구조]
    -1. 후킹 도입 (공감형 질문)
    -2. 상품 요약 (스펙 표)
    -3. 실사용 관점 장점·단점
    -4. 대안 비교 (쿠팡 링크 삽입 지점: {LINK})
    -5. 결론 + 재질문 유도
    -
    -[톤앤매너] 친근한 존댓말, 광고 느낌 최소화 ...`}
    -

    - 실제 팩에는 카테고리별 45종의 프롬프트와 최적화 파라미터가 포함됩니다. -

    -
    -
    -
    - - {/* FAQ */} -
    -
    -

    - 자주 묻는 질문 -

    -
    - {FAQS.map((f, i) => ( -
    - - {openFaq === i && ( -
    - {f.a} -
    - )} -
    - ))} -
    -
    -
    - - {/* FINAL CTA */} -
    -
    -

    - 오늘부터 블로그 수익 자동화. -

    -

    ₩29,000 한 번 결제 · 평생 업데이트

    - -

    - 환불 정책 - {' · '} - 이용약관 -

    -
    -
    - - setAgreeOpen(false)} - productName="블로그 자동화 솔루션 팩" - price="₩29,000" - /> -
    - ); -} diff --git a/app/services/music/layout.tsx b/app/services/music/layout.tsx deleted file mode 100644 index c3fab43..0000000 --- a/app/services/music/layout.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import type { Metadata } from 'next'; - -export const metadata: Metadata = { - title: 'AI 음악 마스터 구조 팩 | Suno · MV · 유튜브 쇼츠', - description: - '엔지니어가 설계한 4단계 AI 음악 제작 공정. Suno 프롬프트 조합법 + MV 비디오 생성 워크플로우 + 저작권 가이드 + 템플릿 PDF + 샘플 프로젝트. 입문 ₩39k / 프로 ₩99k / 마스터 ₩149k.', - keywords: [ - 'AI 음악 만들기', - 'Suno 프롬프트', - 'AI 뮤직비디오', - 'AI 커버곡', - '유튜브 쇼츠 음악', - 'AI 작곡', - '크리에이터 이코노미', - 'Lyria 프롬프트', - 'Runway AI 비디오', - ], - openGraph: { - title: 'AI 음악 마스터 구조 팩 | 쟁승메이드', - description: - '네 사연을 노래로. 쇼츠까지 한 번에. 4단계 AI 음악 공정 · Suno Pro 검증 · 평생 업데이트.', - url: 'https://jaengseung-made.com/services/music', - }, -}; - -export default function MusicLayout({ children }: { children: React.ReactNode }) { - return children; -} diff --git a/app/services/music/page.tsx b/app/services/music/page.tsx deleted file mode 100644 index da2f73c..0000000 --- a/app/services/music/page.tsx +++ /dev/null @@ -1,301 +0,0 @@ -'use client'; - -import { useState } from 'react'; -import Link from 'next/link'; -import PurchaseAgreementModal from '../../components/PurchaseAgreementModal'; -import { SparklesOverlay } from '@/components/ui/sparkles-text'; -import { CardBody, CardContainer, CardItem } from '@/components/ui/3d-card-effect'; - -type Tier = 'starter' | 'pro' | 'master'; - -const TIERS: Record = { - starter: { - name: '입문', - price: '₩39,000', - priceNum: '39,000', - desc: '첫 AI 음악을 위한 필수 구성', - features: [ - 'Suno 프롬프트 조합법 20종', - '구조 템플릿 PDF 40p', - '저작권 가이드 기본판', - '12개월 무료 업데이트', - ], - }, - pro: { - name: '프로', - price: '₩99,000', - priceNum: '99,000', - desc: '쇼츠 업로드까지 완성하는 풀세트', - highlight: true, - features: [ - '입문 전체 포함', - 'MV 워크플로우 (Runway · Luma · Pika)', - '샘플 프로젝트 1개 (.prj · 영상)', - '1:1 Q&A 1회 + 유튜브 SEO 템플릿', - ], - }, - master: { - name: '마스터', - price: '₩149,000', - priceNum: '149,000', - desc: '여러 장르·포맷을 커버하는 마스터피스', - features: [ - '프로 전체 포함', - '샘플 프로젝트 장르별 3종', - '저작권 심화판 + 상업 이용 체크리스트', - '우선 업데이트 · 제작 레시피 영상', - ], - }, -}; - -const PROCESS = [ - { num: '01', subtitle: 'Concept & Lyrics', title: '크리에이티브 디렉팅', result: 'AI 최적화 가사 · 메타데이터 시트' }, - { num: '02', subtitle: 'Music Generation', title: '오디오 엔지니어링', result: '고품질 완곡 (Full Track, 스템 분리본)' }, - { num: '03', subtitle: 'AI MV Generation', title: '비주얼 마스터링', result: '쇼츠(9:16) 또는 유튜브(16:9) 고화질 영상' }, - { num: '04', subtitle: 'Viral Optimization', title: '퍼블리싱 가이드', result: '즉시 업로드 가능한 유튜브 배포 패키지' }, -]; - -const FAQS = [ - { - q: 'Suno 유료 플랜 가입이 꼭 필요한가요?', - a: 'Suno 무료 플랜은 상업적 이용이 제한됩니다. 본인 결과물을 유튜브·SNS에 업로드해 수익화하려면 Suno Pro 이상 권장. 팩 구매 후 가입 전 플랜 선택 가이드가 포함됩니다.', - }, - { - q: '제가 만든 결과물의 상업 이용·저작권은?', - a: '결과물의 상업권은 고객이 가입한 AI 서비스의 이용약관을 따릅니다. 팩에는 Suno·Runway·Luma 각 서비스의 최신 약관 요약과 상업 이용 체크리스트가 포함되어 있습니다. (법률 자문이 아닌 참고용 가이드입니다.)', - }, - { - q: '결과물 품질을 보장하나요?', - a: 'AI 생성물은 모델 버전·프롬프트 입력에 따라 달라지므로 결과물 자체를 보장하지 않습니다. 다만 팩은 동일 프롬프트로 반복 가능한 고품질 구간을 설계하는 방법을 제공합니다. 샘플 쇼츠·프로젝트로 품질 기대치를 사전 확인하세요.', - }, - { - q: '환불이 가능한가요?', - a: '전자상거래법 제17조 제2항 제5호에 따라 디지털 콘텐츠는 제공 시작 후 청약철회가 제한됩니다. 무료 샘플로 사전 확인을 제공하므로 충분히 검토 후 구매해주세요. 파일 손상·전달 불량 등 회사 귀책은 즉시 재전달 또는 환불됩니다.', - }, - { - q: '업데이트는 어떻게 받나요?', - a: '구매자 전용 Notion 페이지에서 변경 이력과 최신 파일을 제공. 12개월간 무료 업데이트가 기본, 마스터는 우선 업데이트·베타 선공개가 포함됩니다.', - }, -]; - -export default function MusicServicePage() { - const [selectedTier, setSelectedTier] = useState(null); - const [openFaq, setOpenFaq] = useState(0); - - return ( -
    - {/* PRICING */} -
    -
    -
    -
    -

    Pricing · 1회 결제

    -

    3개 티어, 목표에 맞게 선택

    -
    - - 샘플 먼저 보기 - -
    - -
    - {(Object.keys(TIERS) as Tier[]).map((key) => { - const t = TIERS[key]; - return ( - - - {t.highlight && ( - - )} - {t.highlight && ( - - - 가장 많이 팔림 - - - )} - - {t.name} - - - {t.desc} - - - {t.price} - 1회 결제 - - - {t.features.map((f) => ( -
  • - · - {f} -
  • - ))} -
    - setSelectedTier(key)} - className={`w-full py-4 rounded-xl font-extrabold text-sm transition-colors ${ - t.highlight - ? 'bg-black hover:bg-black/85 text-white' - : 'bg-white/10 hover:bg-white/20 text-white border border-white/20' - }`} - > - {t.name} 구매하기 - -
    -
    - ); - })} -
    -

    - 구매 전 환불 정책을 반드시 확인해주세요. - 디지털 콘텐츠 특성상 제공 시작 후 청약철회가 제한됩니다. -

    -
    -
    - - {/* 팩 구성품 */} -
    -
    -

    What's Included

    -

    팩 구성품

    -
    - {[ - { title: 'Suno 프롬프트 북', desc: '장르·무드·보컬 톤 조합법 20+종. 복붙해서 바로 사용하는 PDF.' }, - { title: 'MV 워크플로우', desc: 'Midjourney·Runway·Luma로 비트 싱크 영상 만드는 단계별 가이드.' }, - { title: '저작권 & 상업 이용', desc: 'Suno·Runway 약관 요약 + 수익화 전 안전 체크리스트.' }, - { title: '샘플 프로젝트 파일', desc: '완성된 가사·프롬프트·영상 세트. 그대로 수정해 재사용 가능.' }, - ].map((item) => ( -
    -

    {item.title}

    -

    {item.desc}

    -
    - ))} -
    -
    -
    - - {/* PROCESS */} -
    -
    -

    Process

    -

    - 컨셉 → 음악 → 비주얼 → 퍼블리싱 -

    - -
    - {PROCESS.map((step) => ( -
    -

    {step.num}

    -

    - {step.subtitle} -

    -

    {step.title}

    -

    - {step.result} -

    -
    - ))} -
    -
    -
    - - {/* SAMPLES */} -
    -
    -
    -

    Samples

    -

    이 팩으로 만든 실제 쇼츠들

    -
    - - 전체 샘플 갤러리 - -
    -
    - - {/* FAQ */} -
    -
    -

    - 자주 묻는 질문 -

    -
    - {FAQS.map((f, i) => ( -
    - - {openFaq === i && ( -
    - {f.a} -
    - )} -
    - ))} -
    -
    -
    - - {/* Sticky CTA */} -
    -
    -
    -

    From

    -

    - ₩39,000 · 1회 결제 -

    -
    - - 팩 선택하기 - -
    -
    -
    - - {selectedTier && ( - setSelectedTier(null)} - productName={`AI 음악 마스터 팩 · ${TIERS[selectedTier].name}`} - price={TIERS[selectedTier].price} - /> - )} -
    - ); -} diff --git a/app/services/music/samples/page.tsx b/app/services/music/samples/page.tsx deleted file mode 100644 index b0e77a0..0000000 --- a/app/services/music/samples/page.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import type { Metadata } from 'next'; -import Link from 'next/link'; - -export const metadata: Metadata = { - title: 'AI 음악·뮤비 샘플 갤러리', - description: '쟁승메이드 AI 음악 팩으로 제작한 샘플 뮤직비디오 모음. 장르별 결과물을 직접 확인하세요.', -}; - -type Sample = { - id: string; - title: string; - genre: string; - duration: string; - views?: string; - featured?: boolean; - embedId?: string; -}; - -const SAMPLES: Sample[] = [ - { id: 's1', title: 'K-POP 스타일 TOP 샘플', genre: 'K-POP', duration: '0:45', featured: true }, - { id: 's2', title: 'Lo-fi 감성 MV', genre: 'Lo-fi', duration: '1:02' }, - { id: 's3', title: '시티팝 무드 영상', genre: 'City Pop', duration: '0:58' }, - { id: 's4', title: 'EDM 쇼츠 훅', genre: 'EDM', duration: '0:30' }, - { id: 's5', title: '발라드 감성 컷', genre: 'Ballad', duration: '1:10' }, - { id: 's6', title: '트랩 비트 쇼츠', genre: 'Trap', duration: '0:35' }, -]; - -export default function MusicSamplesPage() { - return ( -
    -
    -
    - SAMPLE GALLERY -

    - AI 음악·뮤비 샘플 모음 -

    -

    - 팩 워크플로우로 제작된 결과물입니다. 장르별로 다양한 톤을 확인해보세요. -
    - - 일부 샘플은 런칭 직후 순차 공개됩니다. - -

    -
    - -
    - {SAMPLES.map((s) => ( -
    -
    - - {s.featured && ( - - TOP - - )} - -
    -
    🎬
    -

    {s.genre.toUpperCase()}

    -

    - {s.title} -

    -

    {s.duration}

    -

    - {s.embedId ? '영상 재생' : '영상 준비 중'} -

    -
    -
    - ))} -
    - -
    - NEXT -

    - 내 채널에도 이런 쇼츠 올리고 싶다면 -

    -

    - 동일 워크플로우 팩 ₩39,000부터. -

    - - 팩 가격 보기 - -
    -
    -
    - ); -} diff --git a/app/services/website/layout.tsx b/app/services/website/layout.tsx deleted file mode 100644 index 1d28ddb..0000000 --- a/app/services/website/layout.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import type { Metadata } from 'next'; - -export const metadata: Metadata = { - title: '홈페이지·쇼핑몰·랜딩페이지 제작 | 반응형 웹 개발 외주', - description: - '소상공인·스타트업·기업 홈페이지, 쇼핑몰, 랜딩페이지 제작. 템플릿 없이 직접 개발. Next.js 기반 반응형 웹, SEO 기본 적용. 스타터 20만원~, 계약서 포함, 3개월 유지보수.', - keywords: [ - '홈페이지 제작 외주', - '쇼핑몰 제작 외주', - '랜딩페이지 제작', - '소상공인 홈페이지', - '스타트업 웹사이트', - '반응형 홈페이지 제작', - 'Next.js 개발 외주', - '기업 홈페이지 제작', - '웹사이트 제작 비용', - 'SEO 최적화 홈페이지', - '홈페이지 개발 프리랜서', - ], - openGraph: { - title: '홈페이지·쇼핑몰 제작 | 쟁승메이드', - description: - '소상공인·스타트업 홈페이지 제작. 템플릿 없이 직접 개발, SEO 포함, 20만원~.', - url: 'https://jaengseung-made.com/services/website', - }, - robots: { index: false, follow: false }, -}; - -export default function WebsiteLayout({ children }: { children: React.ReactNode }) { - return children; -} diff --git a/app/services/website/page.tsx b/app/services/website/page.tsx deleted file mode 100644 index 6c551a8..0000000 --- a/app/services/website/page.tsx +++ /dev/null @@ -1,962 +0,0 @@ -'use client'; - -import Link from 'next/link'; -import { useState, useEffect, useRef } from 'react'; -import ContactModal from '../../components/ContactModal'; -import { trackCTAClick } from '../../../lib/gtag'; - -const samples = [ - { - type: 'corporate', - title: '기업 홈페이지', - subtitle: '테크솔루션㈜', - desc: '"홈페이지가 없어서 B2B 영업 때마다 명함만 건넸다"는 고민을 해결한 기업 브랜드 사이트', - gradient: 'linear-gradient(135deg, #0a192f 0%, #112240 50%, #1a3a6c 100%)', - accent: '#4fc3f7', - tags: ['기업', 'B2B', '신뢰'], - icon: '🏢', - }, - { - type: 'bakery', - title: '베이커리 홈페이지', - subtitle: '르 쁘띠 포르', - desc: '"인스타 팔로워는 많은데 실제 방문 예약이 없다"는 F&B 매장의 전환율 문제를 해결한 사이트', - gradient: 'linear-gradient(135deg, #78350f 0%, #92400e 50%, #d97706 100%)', - accent: '#fbbf24', - tags: ['F&B', '로컬', '예약'], - icon: '🥐', - }, - { - type: 'portfolio', - title: '개인 포트폴리오', - subtitle: 'Kim Jisu', - desc: '"링크드인에 PDF 올리면 아무도 안 보더라"는 문제를 해결한 채용·수주 전환형 포트폴리오', - gradient: 'linear-gradient(135deg, #000000 0%, #0d0d0d 50%, #001a00 100%)', - accent: '#00ff88', - tags: ['크리에이터', '디자이너', '수주'], - icon: '✦', - }, - { - type: 'dashboard', - title: '관리자 대시보드', - subtitle: 'DataFlow SaaS', - desc: '"엑셀로 수기 집계하다가 오류가 나서 야근"을 없애는 실시간 데이터 대시보드', - gradient: 'linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #0f2a3a 100%)', - accent: '#38bdf8', - tags: ['SaaS', '자동화', '관리'], - icon: '📊', - }, - { - type: 'game', - title: '게임 매칭 시스템', - subtitle: 'NEXUS ARENA', - desc: '"디스코드에서 수동으로 팀 짜다가 싸움 났다"는 커뮤니티의 매칭·랭킹 자동화 플랫폼', - gradient: 'linear-gradient(135deg, #000000 0%, #0a0a1a 50%, #0d0029 100%)', - accent: '#a855f7', - tags: ['게임', '커뮤니티', '자동화'], - icon: '⚡', - }, - { - type: 'interior', - title: '인테리어 업체 소개', - subtitle: 'AURUM Interior', - desc: '"포트폴리오 사진을 카톡으로만 보내다가 고급 고객을 놓쳤다"는 문제를 해결한 브랜드 사이트', - gradient: 'linear-gradient(135deg, #2C1810 0%, #4A3728 50%, #6B4E37 100%)', - accent: '#D4A853', - tags: ['인테리어', '포트폴리오', '고급'], - icon: '◈', - }, - { - type: 'reading', - title: '독서 기록 노트', - subtitle: '나의 독서 기록', - desc: '읽은 책과 감상을 아름답게 기록하는 나만의 독서 저널 — 이런 것도 만들 수 있습니다', - gradient: 'linear-gradient(135deg, #0C0B09 0%, #1A1710 50%, #2A2218 100%)', - accent: '#D4A853', - tags: ['라이프', '독서', '기록'], - icon: '◻', - }, - { - type: 'shopping', - title: '개인 쇼핑몰', - subtitle: 'MELLOW STUDIO', - desc: '"카페24 기본 테마가 너무 흔해서 브랜드가 안 살아난다"는 고민을 해결한 커스텀 쇼핑몰', - gradient: 'linear-gradient(135deg, #2A2018 0%, #4A3C2C 50%, #7A6A52 100%)', - accent: '#C4A882', - tags: ['쇼핑몰', '패션', '라이프'], - icon: '◇', - }, -]; - -const processSteps = [ - { step: '01', title: '무료 상담', desc: '요구사항 파악 및 방향성 논의', icon: '💬' }, - { step: '02', title: '기획', desc: '사이트맵 & 와이어프레임', icon: '📋' }, - { step: '03', title: '디자인', desc: 'UI/UX 시안 제작', icon: '🎨' }, - { step: '04', title: '개발', desc: '반응형 퍼블리싱 & 기능 구현', icon: '⚙️' }, - { step: '05', title: '납품', desc: '검수 완료 후 도메인 배포', icon: '🚀' }, -]; - -const plans = [ - { - name: '스타터', - price: '20', - unit: '만원~', - color: '#38bdf8', - features: ['5페이지 이내', '반응형 디자인', '기본 SEO 설정', '1개월 유지보수', '3~5영업일 납품'], - note: '개인 블로그, 소규모 소개 사이트', - productId: 'website_starter', - }, - { - name: '비즈니스', - price: '100', - unit: '만원~', - color: '#818cf8', - featured: true, - features: ['10페이지 이내', '반응형 디자인', '관리자 페이지', 'SEO 최적화', '3개월 유지보수', '1~2주 납품'], - note: '기업 사이트, 브랜드 페이지', - productId: 'website_business', - }, - { - name: '프리미엄', - price: '200', - unit: '만원~', - color: '#f472b6', - features: ['페이지 수 무제한', '맞춤 디자인', '결제/회원 시스템', 'DB 연동', '6개월 유지보수', '일정 협의'], - note: '쇼핑몰, SaaS, 복합 시스템', - productId: 'website_premium', - }, -]; - -const faqs = [ - { - q: '제작 기간은 얼마나 걸리나요?', - a: '규모에 따라 다르지만, 스타터는 3~5영업일, 비즈니스는 1~2주, 프리미엄은 협의 후 결정합니다. 빠른 납품이 필요한 경우 별도 상담해 주세요.', - }, - { - q: '수정은 몇 번까지 가능한가요?', - a: '기획 확정 후 디자인 시안 수정은 2회, 개발 완료 후 기능 수정은 유지보수 기간 내 자유롭게 가능합니다. 추가 기능 개발은 별도 견적으로 진행합니다.', - }, - { - q: '도메인과 호스팅도 도와주시나요?', - a: '네, 도메인 구매부터 서버 세팅, 배포까지 전 과정을 도와드립니다. Vercel, AWS, 카페24 등 원하시는 플랫폼에 맞춰 배포해 드립니다.', - }, - { - q: '앱(모바일 앱)이나 쇼핑몰도 개발 가능한가요?', - a: '네. iOS/Android 앱(React Native), 모바일 웹앱, 결제 연동 쇼핑몰, 회원/관리자 시스템 등 모두 개발 가능합니다. 프리미엄 플랜 이상이거나 규모에 따라 별도 견적으로 진행됩니다. 먼저 어떤 기능이 필요한지 상담해 주세요.', - }, - { - q: '계약금은 어떻게 되나요? 중간에 취소하면 어떻게 되나요?', - a: '계약서 체결 후 착수금 30%를 먼저 입금받고 개발을 시작합니다. 납품 전 취소 시 완성 비율에 따라 정산하며, 착수 전 전액 환불됩니다. 모든 조건은 계약서에 명시됩니다.', - }, -]; - -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; -} - -function SampleMiniPreview({ type }: { type: string }) { - const W = 700, H = 350; - const inner = (content: React.ReactNode, bg: string) => ( -
    -
    - {content} -
    -
    - ); - - switch (type) { - case 'corporate': - return inner( -
    -
    -
    TECHSOLUTION
    -
    - {['서비스','솔루션','고객사','연락처'].map(t => {t})} -
    -
    상담 신청
    -
    -
    -
    ENTERPRISE IT SOLUTIONS
    -
    기업 IT 인프라,
    처음부터 끝까지
    -
    15년 경험의 엔터프라이즈 IT 전문 기업.
    클라우드·보안·DX 통합 솔루션을 제공합니다.
    -
    -
    무료 상담 신청
    -
    서비스 소개서
    -
    -
    - {[['15+','년 업력'],['340+','완료 프로젝트'],['180+','기업 고객'],['99.9%','가동률']].map(([n,l]) => ( -
    {n}
    {l}
    - ))} -
    -
    -
    , '#fff' - ); - - case 'bakery': - return inner( -
    -
    -
    Le Petit Fort
    ARTISAN BOULANGERIE
    -
    - {['메뉴','스토리','예약'].map(t => {t})} -
    -
    방문 예약
    -
    -
    -
    -
    Since 2018 · Paris Recipe
    -
    매일 아침
    구워내는
    정직한 빵
    -
    프랑스산 에슈레 버터와 천연 발효종만으로
    만드는 정직한 아르티장 베이커리.
    -
    -
    오늘의 빵 보기
    -
    매장 안내
    -
    -
    -
    - {[{n:'버터 크루아상',p:'3,200',c:'#d97706'},{n:'소금빵',p:'2,800',c:'#b45309'},{n:'딸기 케이크',p:'7,500',c:'#be185d'},{n:'캄파뉴',p:'8,900',c:'#065f46'}].map(item => ( -
    -
    -
    {item.n}
    -
    ₩{item.p}
    -
    - ))} -
    -
    -
    , '#fffbf5' - ); - - case 'portfolio': - return inner( -
    -
    -
    -
    KJ_
    -
    - {['About','Work','Skills','Contact'].map(t => {t})} -
    -
    -
    - Available -
    HIRE ME
    -
    -
    -
    -
    -
    -
    FULL-STACK DEVELOPER
    -
    Kim
    Jisu
    -
    React · Next.js · TypeScript · Node.js
    디자인과 코드의 경계를 탐험합니다.
    -
    -
    VIEW WORK
    -
    CONTACT
    -
    -
    -
    -
    - KJ -
    -
    -
    -
    , '#000' - ); - - case 'dashboard': - return inner( -
    -
    -
    DataFlow
    - {['대시보드','분석','리포트','사용자','설정'].map((item, i) => ( -
    {item}
    - ))} -
    -
    -
    -
    실시간 현황
    -
    이번 달
    -
    -
    - {[{l:'총 매출',v:'₩48.2M',c:'#38bdf8',u:true},{l:'신규 사용자',v:'1,247',c:'#34d399',u:true},{l:'전환율',v:'12.4%',c:'#a78bfa',u:false}].map(s => ( -
    -
    {s.l}
    -
    {s.v}
    -
    {s.u ? '↑ +8.3%' : '↓ -1.2%'}
    -
    - ))} -
    -
    -
    월간 매출 추이
    -
    - {[40,55,35,65,80,60,90,75,85,95,70,100].map((h, i) => ( -
    - ))} -
    -
    -
    -
    , '#0f172a' - ); - - case 'game': - return inner( -
    -
    -
    -
    -
    NEXUSARENA
    -
    - {['랭킹','매칭','챔피언','스토어'].map(t => {t})} -
    -
    PLAY NOW
    -
    -
    -
    -
    SEASON 7 · COMPETITIVE
    -
    NEXUS
    ARENA
    -
    실시간 매칭 · 랭크 시스템 · 글로벌 토너먼트
    지금 바로 전장에 참전하세요.
    -
    -
    PLAY NOW
    -
    랭킹 보기
    -
    -
    -
    - {[{name:'VIPER',role:'Assassin',c:'#06b6d4'},{name:'NOVA',role:'Mage',c:'#a855f7'},{name:'IRON',role:'Tank',c:'#94a3b8'},{name:'KIRA',role:'Support',c:'#ec4899'}].map(ch => ( -
    -
    -
    -
    -
    {ch.name}
    -
    {ch.role}
    -
    - ))} -
    -
    -
    , '#000' - ); - - case 'interior': - return inner( -
    -
    -
    AURUM
    INTERIOR DESIGN
    -
    - {['포트폴리오','서비스','견적 문의'].map(t => {t})} -
    -
    CONTACT
    -
    -
    -
    -
    Premium Interior Design
    -
    공간이
    이야기가
    되는 순간
    -
    20년 경험의 인테리어 전문가가
    당신만의 공간을 완성합니다.
    -
    포트폴리오 보기
    -
    -
    - {['linear-gradient(135deg, #c9b99a, #a8927a)','linear-gradient(135deg, #8B7355, #6B5A47)','linear-gradient(135deg, #D4C5A9, #B8A88A)','linear-gradient(135deg, #7C6555, #5C4A3A)'].map((bg, i) => ( -
    - ))} -
    -
    -
    , '#faf8f4' - ); - - case 'reading': - return inner( -
    -
    -
    나의 독서 기록
    -
    - {['서재','월별 기록','통계'].map(t => {t})} -
    -
    -
    -
    -
    My Reading Journal
    -
    읽은 책들이
    별처럼
    빛나는 공간
    -
    독서 기록을 아름답게.
    감상과 인용구를 나만의 서재에 담아보세요.
    -
    기록 시작하기
    -
    - {[['47','완독'],['1,240','페이지'],['12','이번 달']].map(([n,l]) => ( -
    {n}
    {l}
    - ))} -
    -
    -
    - {[{h:130,bg:'linear-gradient(180deg,#1e3a5f,#0a1628)',sp:'#2563eb'},{h:152,bg:'linear-gradient(180deg,#2C1810,#1a0e0a)',sp:'#D4A853'},{h:118,bg:'linear-gradient(180deg,#1a1a1a,#0d0d0d)',sp:'#6b7280'},{h:142,bg:'linear-gradient(180deg,#1e1b4b,#0f0d2e)',sp:'#7c3aed'},{h:120,bg:'linear-gradient(180deg,#064e3b,#022c22)',sp:'#10b981'}].map((b, i) => ( -
    -
    -
    - ))} -
    -
    -
    , '#0C0B09' - ); - - case 'shopping': - return inner( -
    -
    -
    MELLOW STUDIO
    -
    - {['NEW','OUTER','TOP','BOTTOM'].map(t => {t})} -
    -
    🔍🛍 2
    -
    -
    -
    -
    -
    -
    NEW ARRIVAL
    -
    SS 2025
    -
    -
    -
    -
    -
    COLLECTION
    -
    Quiet
    Luxury
    -
    소음 없이 존재하는 옷.
    절제된 아름다움을 입으세요.
    -
    SHOP NOW
    -
    -
    - {[['#c8b89a','₩328K'],['#8a7860','₩498K'],['#d4c5a9','₩218K']].map(([bg, p], i) => ( -
    -
    -
    {p}
    -
    - ))} -
    -
    -
    -
    , '#F4F2EF' - ); - - default: - return
    ; - } -} - -export default function WebsiteServicePage() { - const [openFaq, setOpenFaq] = useState(null); - const [showTop, setShowTop] = useState(false); - const [modalOpen, setModalOpen] = useState(false); - const [modalService, setModalService] = useState('홈페이지 제작'); - - const openModal = (service: string) => { - trackCTAClick(service, '/services/website'); - setModalService(service); - setModalOpen(true); - }; - - 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 ( -
    - setModalOpen(false)} - service={modalService} - checklist={[ - '원하시는 홈페이지 종류 (소개/쇼핑몰/SaaS 등)', - '참고하고 싶은 사이트 URL (있으면)', - '필요한 주요 페이지 및 기능', - '희망 납품 일정 및 예산 범위', - '디자인 선호 스타일 (모던/감성/심플 등)', - ]} - accentColor="text-indigo-400" - headerFrom="#0a0a1a" - headerTo="#1e1b4b" - /> - - - {/* Back Banner */} -
    - - ← 홈페이지 제작 서비스로 돌아가기 - - | - - SAMPLE · 베이커리 홈페이지 - -
    - - {/* Navbar */} - - - {/* Hero */} -
    - {/* Decorative circles */} -
    -
    - - {/* SVG Croissant illustration */} -
    - - {/* Croissant shape */} - - - {/* Layered flakes */} - - - - {/* Shine */} - - {/* Steam */} - - - - -
    - - {/* Wheat decoration top right */} - - - {[15, 35, 55, 75].map((y, i) => ( - - - - - ))} - - -
    -
    - - 오늘도 새벽 4시부터 굽고 있습니다 -
    - -
    - “매일 아침, 정성을 굽습니다” -
    -

    - 갓 구운 빵의
    - 따뜻한 향기
    - 기다립니다 -

    -

    - 파리 전통 방식으로 매일 새벽 4시부터
    정성껏 굽는 르 쁘띠 포르의 빵을 만나보세요. -

    - - {/* Social proof */} -
    -
    - {['#d97706', '#b45309', '#92400e', '#78350f'].map((c, i) => ( -
    0 ? -8 : 0 }} /> - ))} -
    -
    -
    - {[1,2,3,4,5].map(i => ( - - ))} -
    - 4.9점 · 1,200+ 리뷰 -
    -
    - -
    - - -
    -
    -
    - - {/* Season Special Banner */} -
    -
    - - Spring Limited -
    - | - - 🌸 딸기 타르틀렛 — 4월 한정 메뉴 출시 - - | - 자세히 보기 → -
    - - {/* Menu */} -
    -
    -
    -
    - Today's Menu -
    -

    - 오늘의 추천 메뉴 -

    -

    - 매일 새벽 구운 신선한 빵을 만나보세요 -

    -
    -
    - {menuItems.map((item) => ( -
    - {/* Card visual — SVG pattern instead of emoji */} -
    - {/* Subtle dotted pattern */} - - - - - - - {/* Bread silhouette SVG */} - - - - - - - - {item.tag} -
    -
    -
    - {item.name} -
    -
    - {item.desc} -
    -
    - {item.ingredients.map(ig => ( - {ig} - ))} -
    -
    - - ₩{item.price} - - -
    -
    -
    - ))} -
    -
    -
    - - {/* Seasonal Specials */} -
    -
    -
    -
    - Seasonal Specials -
    -

    - 계절마다 새로운 감동 -

    -
    -
    - {specials.map((s) => ( -
    -
    -
    -
    -
    -
    {s.season} 한정
    -
    {s.item}
    -
    {s.desc}
    -
    - ))} -
    -
    -
    - - {/* Story */} -
    -
    -
    -
    - Our Story -
    -

    - 2009년부터
    한 자리를 지켜온
    - 우리 동네 빵집 -

    -

    - 파리에서 5년간 수업한 오너 셰프가 고향 서울로 돌아와 차린 작은 베이커리. 대기업 프랜차이즈가 넘쳐나는 세상에서도 손으로 빚고, 눈으로 확인하는 전통 방식을 고집합니다. -

    -

    - 밀가루, 버터, 소금, 물. 단 네 가지 재료로 만드는 우리의 빵에는 흉내낼 수 없는 진심이 담겨있습니다. -

    -
    - {[{ n: '15+', l: '년 경력' }, { n: '200+', l: '종류의 빵' }, { n: '4시', l: '매일 기상' }].map((s) => ( -
    -
    {s.n}
    -
    {s.l}
    -
    - ))} -
    -
    - - {/* Chef card with SVG illustration */} -
    - {/* Pattern overlay */} - - - - - - - {/* Chef SVG illustration */} -
    -
    - - {/* Chef hat */} - - - - {/* Face */} - - - - - -
    -
    - Chef Kim Dongwoo -
    -
    - Le Cordon Bleu Paris 졸업
    - 2009년 르 쁘띠 포르 창업 -
    - {/* Awards */} -
    - {['미쉐린 추천', '블루리본', '로컬 레전드'].map(award => ( - {award} - ))} -
    -
    -
    -
    -
    - - {/* Customer Reviews */} -
    -
    -
    -
    - Guest Reviews -
    -

    - 고객들의 이야기 -

    -
    - {[1,2,3,4,5].map(i => ( - - ))} - 4.9 -  (1,243개 리뷰) -
    -
    -
    - {reviews.map((r) => ( -
    - {/* Stars */} -
    - {[1,2,3,4,5].map(i => ( - - ))} - {r.verified && ( - - ✓ 인증 방문 - - )} -
    - {/* Quote SVG */} - - - -

    - {r.text} -

    -
    -
    - {r.name[0]} -
    -
    -
    {r.name}
    -
    {r.date}
    -
    -
    -
    - ))} -
    -
    -
    - - {/* Hours & Location */} -
    -
    -
    -
    Hours
    -

    운영 시간

    -
    - {hours.map((h) => ( -
    - {h.day} - {h.time} -
    - ))} -
    -
    -

    - ⚡ 품절 시 조기 마감될 수 있습니다.
    - 인스타그램에서 당일 재고를 확인하세요. -

    -
    -
    -
    -
    Location
    -

    매장 위치

    -

    - 서울특별시 마포구 연남동 224-14
    연남로 68 르 쁘띠 포르 -

    -
    - {[ - { icon: 'M', text: '2호선 홍대입구역 3번 출구 도보 5분' }, - { icon: 'T', text: '02-334-5678' }, - { icon: '@', text: '@lepetitfort_seoul' }, - ].map((info) => ( -
    -
    - {info.icon} -
    - {info.text} -
    - ))} -
    -
    -
    -
    - - {/* CTA — Custom Cake */} -
    -
    - - Custom Order -
    -

    - 특별한 날을 위한 케이크 -

    -

    - 생일, 기념일, 웨딩 케이크까지.
    - 최소 3일 전 예약 시 원하시는 케이크를 제작해드립니다. -

    -

    - 가격 상담 무료 · 사진 참고 가능 · 직접 수령 또는 배달 가능 -

    - -
    - - {/* Footer */} -
    -
    -
    - Le Petit Fort — Artisan Boulangerie -
    -
    - © 2024 르 쁘띠 포르. All rights reserved. -
    -
    -
    - {['Instagram', 'Naver Map', 'Kakao'].map((s) => ( - {s} - ))} -
    -
    -
    - ); -} diff --git a/app/services/website/samples/corporate/page.tsx b/app/services/website/samples/corporate/page.tsx deleted file mode 100644 index 8cab80e..0000000 --- a/app/services/website/samples/corporate/page.tsx +++ /dev/null @@ -1,279 +0,0 @@ -import Link from 'next/link'; - -export default function CorporateSample() { - const services = [ - { - title: 'IT 인프라 구축', - desc: '기업 맞춤형 서버 환경 설계부터 클라우드 마이그레이션까지, 안정적인 IT 기반을 구축합니다.', - detail: '온프레미스 · 하이브리드 클라우드 · AWS · Azure', - icon: ( - - - - ), - }, - { - title: '사이버 보안 솔루션', - desc: '최신 위협에 대응하는 엔터프라이즈급 보안 시스템. 침해사고 예방부터 대응까지 통합 관리합니다.', - detail: 'ISMS · 취약점 분석 · 보안 모니터링 · 컴플라이언스', - icon: ( - - - - ), - }, - { - title: '디지털 전환 (DX)', - desc: '레거시 시스템을 현대화하고 비즈니스 프로세스를 자동화하는 DX 컨설팅을 제공합니다.', - detail: 'ERP 연동 · 프로세스 자동화 · 데이터 시각화 · AI 도입', - icon: ( - - - - ), - }, - ]; - - const stats = [ - { num: '15+', label: '년 업력' }, - { num: '340+', label: '완료 프로젝트' }, - { num: '180+', label: '기업 고객사' }, - { num: '99.9%', label: '서비스 가동률' }, - ]; - - const certs = ['AWS Partner', 'ISO 27001', 'ISMS-P 인증', 'Microsoft Partner', 'Google Cloud']; - - const clients = ['삼성전자', 'LG유플러스', '현대모비스', 'SK하이닉스', 'KT', '신한은행', 'NH농협', '롯데정보통신']; - - const testimonials = [ - { - quote: '마이그레이션 기간 동안 단 한 번의 서비스 중단도 없었습니다. 완벽한 이전이었습니다.', - name: '이○○ CTO', - company: '핀테크 스타트업', - }, - { - quote: '보안 감사 이후 취약점 제로. 컴플라이언스 대응이 이렇게 빠를 수 있다는 게 놀라웠습니다.', - name: '박○○ IT팀장', - company: '중견 제조사', - }, - ]; - - return ( -
    - - - {/* Back Banner */} -
    - - ← 홈페이지 제작 서비스로 돌아가기 - - | - SAMPLE · 기업 홈페이지 -
    - - {/* Navbar */} - - - {/* Hero */} -
    - {/* Animated grid */} -
    -
    - - {/* Floating tech nodes */} - {[ - { x: '68%', y: '20%', delay: '0s', size: 6, color: '#60a5fa' }, - { x: '78%', y: '55%', delay: '1s', size: 4, color: '#a78bfa' }, - { x: '85%', y: '35%', delay: '2s', size: 8, color: '#34d399' }, - { x: '72%', y: '72%', delay: '0.5s', size: 5, color: '#60a5fa' }, - ].map((dot, i) => ( -
    - ))} - - {/* SVG Tech Illustration */} - - - - - - - - - - - -
    -
    -
    - Enterprise IT Solutions -
    -

    - 디지털 혁신으로
    - 비즈니스의 미래
    - 설계합니다 -

    -

    - 15년의 경험과 검증된 기술력으로 기업의 IT 인프라를 혁신합니다.
    - 클라우드, 보안, 디지털 전환까지 원스톱으로 제공합니다. -

    -
    - - -
    -
    -
    - - {/* Stats Bar */} -
    -
    - {stats.map((s, i) => ( -
    -
    {s.num}
    -
    {s.label}
    -
    - ))} -
    -
    - - {/* Certifications */} -
    -
    - 인증 · 파트너십 - {certs.map((c) => ( -
    - {c} -
    - ))} -
    -
    - - {/* Services */} -
    -
    -
    -
    Our Services
    -

    핵심 서비스

    -

    기업의 성장을 이끄는 검증된 IT 솔루션

    -
    -
    - {services.map((svc, i) => ( -
    -
    -
    - {svc.icon} -
    -

    {svc.title}

    -

    {svc.desc}

    -
    {svc.detail}
    -
    - 자세히 보기 - -
    -
    - ))} -
    -
    -
    - - {/* Testimonials */} -
    -
    -
    -
    Client Reviews
    -

    고객 후기

    -
    -
    - {testimonials.map((t, i) => ( -
    -
    "
    -

    {t.quote}

    -
    -
    - {t.name[0]} -
    -
    -
    {t.name}
    -
    {t.company}
    -
    -
    -
    - ))} -
    -
    -
    - - {/* Clients */} -
    -
    -
    Trusted By Leading Companies
    -
    - {clients.map((c) => ( -
    {c}
    - ))} -
    -
    -
    - - {/* Contact CTA */} -
    -
    -
    Get Started
    -

    - 프로젝트를 시작하세요 -

    -

    - IT 솔루션이 필요하시면 언제든지 연락해주세요.
    - 전담 컨설턴트가 최적의 방안을 제안해드립니다. -

    -
    - - -
    -
    -
    - - {/* Footer */} -
    -
    © 2024 ㈜테크솔루션. All rights reserved.
    -
    서울특별시 강남구 테헤란로 123 테크타워 15F
    -
    -
    - ); -} diff --git a/app/services/website/samples/dashboard/page.tsx b/app/services/website/samples/dashboard/page.tsx deleted file mode 100644 index 33bce94..0000000 --- a/app/services/website/samples/dashboard/page.tsx +++ /dev/null @@ -1,436 +0,0 @@ -'use client'; - -import Link from 'next/link'; -import { useState } from 'react'; - -const kpis = [ - { label: '월 활성 사용자', value: '124,832', change: '+12.4%', up: true, color: '#3b82f6', sparkline: [40, 55, 45, 70, 60, 85, 100] }, - { label: '월 매출', value: '₩284M', change: '+8.7%', up: true, color: '#10b981', sparkline: [50, 60, 55, 75, 80, 78, 100] }, - { label: '전환율', value: '3.62%', change: '-0.3%', up: false, color: '#f59e0b', sparkline: [90, 80, 85, 75, 70, 72, 68] }, - { label: '고객 만족도', value: '4.8', change: '+0.2', up: true, color: '#8b5cf6', sparkline: [70, 72, 74, 76, 78, 80, 85] }, -]; - -const lineData = [ - { month: 'Jan', revenue: 65, users: 48 }, - { month: 'Feb', revenue: 78, users: 55 }, - { month: 'Mar', revenue: 72, users: 52 }, - { month: 'Apr', revenue: 89, users: 64 }, - { month: 'May', revenue: 95, users: 71 }, - { month: 'Jun', revenue: 82, users: 66 }, - { month: 'Jul', revenue: 110, users: 88 }, - { month: 'Aug', revenue: 128, users: 100 }, -]; - -const activities = [ - { user: 'lee@company.com', action: '프리미엄 플랜 구독', time: '2분 전', status: 'success', avatar: 'L' }, - { user: 'park@startup.io', action: 'API 한도 초과 경고', time: '14분 전', status: 'warning', avatar: 'P' }, - { user: 'kim@corp.kr', action: '팀 멤버 5명 초대', time: '31분 전', status: 'info', avatar: 'K' }, - { user: 'choi@brand.com', action: '결제 실패 (카드 만료)', time: '1시간 전', status: 'error', avatar: 'C' }, - { user: 'jung@agency.co', action: '새 워크스페이스 생성', time: '2시간 전', status: 'success', avatar: 'J' }, -]; - -const menus = [ - { id: 'overview', label: 'Overview', dot: '#3b82f6' }, - { id: 'analytics', label: 'Analytics', dot: '#10b981' }, - { id: 'users', label: 'Users', dot: null }, - { id: 'revenue', label: 'Revenue', dot: null }, - { id: 'reports', label: 'Reports', dot: null }, - { id: 'settings', label: 'Settings', dot: null }, -]; - -const channels = [ - { label: 'Organic Search', val: 78, color: '#3b82f6' }, - { label: 'Direct', val: 55, color: '#10b981' }, - { label: 'Social Media', val: 42, color: '#a855f7' }, - { label: 'Email', val: 34, color: '#f59e0b' }, - { label: 'Referral', val: 20, color: '#ec4899' }, -]; - -const alerts = [ - { type: 'error', msg: 'API 응답 지연 (p99 > 2s)', time: '5분 전' }, - { type: 'warning', msg: '스토리지 사용량 85% 초과', time: '32분 전' }, - { type: 'success', msg: '일일 백업 완료', time: '1시간 전' }, -]; - -const statusColor: Record = { success: '#10b981', warning: '#f59e0b', error: '#ef4444', info: '#3b82f6' }; - -function SparkLine({ data, color }: { data: number[]; color: string }) { - const max = Math.max(...data); - const min = Math.min(...data); - const h = 28; - const w = 72; - const step = w / (data.length - 1); - const pts = data.map((v, i) => { - const x = i * step; - const y = h - ((v - min) / (max - min || 1)) * h; - return `${x},${y}`; - }).join(' '); - return ( - - - - - ); -} - -function LineChart({ data }: { data: typeof lineData }) { - const chartH = 130; - const chartW = 440; - const padL = 32; - const padB = 24; - const innerW = chartW - padL; - const innerH = chartH - padB; - const maxRev = Math.max(...data.map(d => d.revenue)); - - const revPts = data.map((d, i) => { - const x = padL + (i / (data.length - 1)) * innerW; - const y = (1 - d.revenue / maxRev) * innerH; - return `${x},${y}`; - }).join(' '); - - const usrPts = data.map((d, i) => { - const x = padL + (i / (data.length - 1)) * innerW; - const y = (1 - d.users / maxRev) * innerH; - return `${x},${y}`; - }).join(' '); - - return ( - - {/* Grid lines */} - {[0, 0.25, 0.5, 0.75, 1].map((t, i) => ( - - - - {Math.round(maxRev * (1 - t))} - - - ))} - {/* Area fills */} - - - - - - - - - - - - - {/* Lines */} - - - {/* Dots at last point */} - {[{ pts: revPts, color: '#3b82f6' }, { pts: usrPts, color: '#10b981' }].map(({ pts: p, color }) => { - const last = p.split(' ').pop()!; - const [lx, ly] = last.split(',').map(Number); - return ; - })} - {/* X axis labels */} - {data.map((d, i) => ( - {d.month} - ))} - - ); -} - -export default function DashboardSample() { - const [activeMenu, setActiveMenu] = useState('overview'); - const [alertsVisible, setAlertsVisible] = useState(true); - - return ( -
    - - - {/* Back Banner */} -
    - - ← 홈페이지 제작 서비스로 돌아가기 - - | - - SAMPLE · 관리자 대시보드 - -
    - -
    - {/* Sidebar */} - - - {/* Main */} -
    - {/* Top bar */} -
    -
    -
    - - - - - -
    -
    -
    - - {/* Alert bell */} - - -
    -
    - -
    - {/* Alerts panel */} - {alertsVisible && ( -
    -
    -
    시스템 알림
    - -
    -
    - {alerts.map((a, i) => ( -
    -
    -
    -
    {a.msg}
    -
    {a.time}
    -
    -
    - ))} -
    -
    - )} - - {/* Page header */} -
    -
    -

    Overview

    -
    2024.08.14 · 오전 10:32 업데이트
    -
    -
    - - {/* KPI Cards */} -
    - {kpis.map((kpi) => ( -
    -
    -
    {kpi.label}
    - -
    -
    {kpi.value}
    -
    - {kpi.up ? '↑' : '↓'} {kpi.change} -
    -
    - ))} -
    - - {/* Charts row */} -
    - {/* Line Chart */} -
    -
    -
    월별 매출 & 사용자 추이
    -
    -
    -
    - 매출 -
    -
    -
    - 사용자 -
    -
    - {['1M', '3M', '6M', '1Y'].map((p) => ( - - ))} -
    -
    -
    - -
    - - {/* Channel Progress */} -
    -
    채널별 전환율
    - {channels.map((p) => ( -
    -
    - {p.label} - {p.val}% -
    -
    -
    -
    -
    - ))} - {/* Donut summary */} -
    - - {(() => { - const total = channels.reduce((s, c) => s + c.val, 0); - let offset = 0; - const r = 20; - const circ = 2 * Math.PI * r; - return channels.map((c) => { - const dash = (c.val / total) * circ; - const el = ( - - ); - offset += dash; - return el; - }); - })()} - - ALL - -
    - Organic 채널이
    - 최고 전환율 78%
    - 달성 중 -
    -
    -
    -
    - - {/* Activity Table */} -
    -
    -
    최근 활동
    - -
    - - - - {['사용자', '활동', '시간', '상태'].map((h) => ( - - ))} - - - - {activities.map((a, i) => ( - - - - - - - ))} - -
    {h}
    -
    -
    {a.avatar}
    - {a.user} -
    -
    {a.action}{a.time} -
    -
    - - {a.status === 'success' ? 'OK' : a.status === 'warning' ? 'WARN' : a.status === 'error' ? 'ERR' : 'INFO'} - -
    -
    -
    -
    -
    -
    -
    - ); -} diff --git a/app/services/website/samples/game/page.tsx b/app/services/website/samples/game/page.tsx deleted file mode 100644 index 6adaadc..0000000 --- a/app/services/website/samples/game/page.tsx +++ /dev/null @@ -1,428 +0,0 @@ -'use client'; - -import Link from 'next/link'; -import { useState, useEffect } from 'react'; - -const rankings = [ - { rank: 1, name: 'ShadowViper_KR', score: 9_842, tier: 'GRANDMASTER', wins: 312, kda: '18.4', change: '+2' }, - { rank: 2, name: 'NightFalcon', score: 9_610, tier: 'GRANDMASTER', wins: 289, kda: '15.2', change: '0' }, - { rank: 3, name: 'Xenon_X', score: 9_241, tier: 'MASTER', wins: 267, kda: '12.9', change: '+1' }, - { rank: 4, name: 'KR_Dominator', score: 8_970, tier: 'MASTER', wins: 251, kda: '11.7', change: '-1' }, - { rank: 5, name: 'Pulse_Wave', score: 8_834, tier: 'DIAMOND', wins: 238, kda: '10.3', change: '+3' }, -]; - -const modes = [ - { id: 'solo', name: 'SOLO', sub: '1 vs 1', desc: '순수한 실력으로 맞붙는 1대1 대결', color: '#06b6d4', players: '12,400', season: 'S7' }, - { id: 'duo', name: 'DUO', sub: '2 vs 2', desc: '파트너와 함께하는 전략적 팀플레이', color: '#a855f7', players: '28,700', season: 'S7' }, - { id: 'squad', name: 'SQUAD', sub: '5 vs 5', desc: '전략과 팀워크로 승리를 쟁취', color: '#f59e0b', players: '7,100', season: 'S7' }, -]; - -const recentMatches = [ - { result: 'WIN', mode: 'DUO', duration: '18:32', kills: 12, deaths: 2, assists: 8, rating: '+32' }, - { result: 'WIN', mode: 'SOLO', duration: '22:11', kills: 8, deaths: 1, assists: 4, rating: '+24' }, - { result: 'LOSS', mode: 'SQUAD', duration: '31:45', kills: 5, deaths: 5, assists: 12, rating: '-18' }, - { result: 'WIN', mode: 'DUO', duration: '15:20', kills: 15, deaths: 3, assists: 6, rating: '+40' }, -]; - -const champions = [ - { name: 'VIPER', role: 'Assassin', color: '#06b6d4', power: 92, winRate: '63%' }, - { name: 'KIRA', role: 'Support', color: '#ec4899', power: 78, winRate: '58%' }, - { name: 'IRON', role: 'Tank', color: '#94a3b8', power: 85, winRate: '55%' }, - { name: 'NOVA', role: 'Mage', color: '#a855f7', power: 88, winRate: '61%' }, -]; - -const tierColor: Record = { - GRANDMASTER: '#fbbf24', - MASTER: '#a855f7', - DIAMOND: '#60a5fa', -}; - -const tierIcon = (tier: string) => ( - - - - -); - -export default function GameSample() { - const [onlinePlayers, setOnlinePlayers] = useState(48_219); - const [matchingCount, setMatchingCount] = useState(1_342); - const [matchingActive, setMatchingActive] = useState(false); - const [matchTimer, setMatchTimer] = useState(0); - const [selectedChampion, setSelectedChampion] = useState(0); - const [seasonProgress] = useState(67); - - useEffect(() => { - const interval = setInterval(() => { - setOnlinePlayers((p) => p + Math.floor(Math.random() * 6 - 2)); - setMatchingCount((c) => c + Math.floor(Math.random() * 4 - 1)); - }, 2000); - return () => clearInterval(interval); - }, []); - - useEffect(() => { - let timer: ReturnType; - if (matchingActive) { - timer = setInterval(() => setMatchTimer((t) => t + 1), 1000); - } else { - setMatchTimer(0); - } - return () => clearInterval(timer); - }, [matchingActive]); - - return ( -
    - - - {/* Back Banner */} -
    - - ← 홈페이지 제작 서비스로 돌아가기 - - | - - SAMPLE · 게임 매칭 시스템 - -
    - - {/* Navbar */} - - - {/* Hero */} -
    - {/* Grid */} -
    - {/* Scan */} -
    - - {/* Floating particles */} - {[ - { left: '10%', top: '20%', size: 4, delay: '0s', color: '#06b6d4' }, - { left: '85%', top: '30%', size: 6, delay: '1s', color: '#a855f7' }, - { left: '20%', top: '70%', size: 3, delay: '2s', color: '#06b6d4' }, - { left: '75%', top: '65%', size: 5, delay: '0.5s', color: '#f59e0b' }, - { left: '50%', top: '15%', size: 3, delay: '1.5s', color: '#a855f7' }, - { left: '60%', top: '80%', size: 4, delay: '2.5s', color: '#10b981' }, - ].map((p, i) => ( -
    - ))} - - {/* Corner brackets */} - {[ - { top: 40, left: 40, borderTop: '2px solid #06b6d4', borderLeft: '2px solid #06b6d4' }, - { top: 40, right: 40, borderTop: '2px solid #a855f7', borderRight: '2px solid #a855f7' }, - { bottom: 40, left: 40, borderBottom: '2px solid #06b6d4', borderLeft: '2px solid #06b6d4' }, - { bottom: 40, right: 40, borderBottom: '2px solid #a855f7', borderRight: '2px solid #a855f7' }, - ].map((s, i) => ( -
    - ))} - -
    -
    - Season 7 · RANKED MATCH -
    -

    - NEXUS
    - ARENA -

    -

    - ENTER THE ARENA. CLAIM YOUR GLORY. -

    - - {/* Live Stats */} -
    - {[ - { label: 'ONLINE', val: onlinePlayers.toLocaleString(), color: '#06b6d4' }, - { label: 'IN MATCH', val: matchingCount.toLocaleString(), color: '#a855f7' }, - { label: 'SERVERS', val: '24', color: '#10b981' }, - { label: 'AVG WAIT', val: '< 30s', color: '#f59e0b' }, - ].map((s) => ( -
    -
    {s.val}
    -
    {s.label}
    -
    - ))} -
    - - {/* Match button */} - {!matchingActive ? ( - - ) : ( -
    -
    - MATCHING... {String(Math.floor(matchTimer / 60)).padStart(2, '0')}:{String(matchTimer % 60).padStart(2, '0')} -
    - -
    - )} -
    -
    - - {/* Season Pass */} -
    -
    -
    -
    -
    SEASON 7 PASS
    -
    - Lv. 42 - / 100 -
    -
    -
    -
    - {seasonProgress}% 완료 - 다음 보상까지 1,840 XP -
    -
    -
    -
    -
    -
    - {['스킨 3개', '이모트 5개', '칭호 2개', '골드 5,000'].map((reward) => ( -
    - {reward} -
    - ))} -
    -
    -
    -
    - - {/* Champion Select */} -
    -
    -
    -
    -
    // ROSTER
    -

    - CHAMPIONS. -

    -
    - -
    -
    - {champions.map((c, i) => ( -
    setSelectedChampion(i)} - // @ts-expect-error CSS variable - style={{ '--champ-color': c.color, border: `1px solid ${selectedChampion === i ? c.color : c.color + '25'}`, borderRadius: 6, padding: '22px 18px', background: selectedChampion === i ? c.color + '10' : 'rgba(0,0,0,0.6)', position: 'relative', overflow: 'hidden' }} - > - {selectedChampion === i && ( -
    -
    SELECTED
    -
    - )} -
    - {/* Champion SVG silhouette */} -
    - - - - - -
    -
    {c.name}
    -
    {c.role}
    -
    -
    - POWER - {c.power} -
    -
    -
    -
    -
    -
    - Win Rate: {c.winRate} -
    -
    - ))} -
    -
    -
    - - {/* Game Modes */} -
    -
    -
    -

    - GAME MODES -

    -
    -
    -
    - {modes.map((mode) => ( -
    -
    - {/* Mode icon */} -
    - - {mode.id === 'solo' && } - {mode.id === 'duo' && <>} - {mode.id === 'squad' && <>} - -
    -
    -
    {mode.name}
    -
    {mode.sub}
    -
    -
    {mode.desc}
    -
    -
    -
    {mode.players} IN QUEUE
    -
    AVG WAIT: < 30s
    -
    - -
    -
    - ))} -
    -
    -
    - - {/* Rankings + Recent Matches */} -
    -
    - {/* Rankings */} -
    -
    -

    - GLOBAL RANKING. -

    -
    Season 7 · Top 100
    -
    -
    -
    - {['RANK', 'PLAYER', 'SCORE', 'WINS', 'K/D/A'].map((h) => ( -
    {h}
    - ))} -
    - {rankings.map((r, i) => ( -
    -
    - {r.rank < 10 ? `0${r.rank}` : r.rank} -
    -
    -
    - {tierIcon(r.tier)} - {r.name} -
    -
    - {r.tier} - - {r.change === '0' ? '–' : r.change} - -
    -
    -
    {r.score.toLocaleString()}
    -
    {r.wins}
    -
    {r.kda}
    -
    - ))} -
    -
    - - {/* Recent Matches */} -
    -
    -

    - RECENT MATCHES. -

    -
    Last 10 games
    -
    -
    - {recentMatches.map((m, i) => ( -
    -
    -
    {m.result}
    -
    {m.mode}
    -
    -
    -
    - {m.kills} / {m.deaths} / {m.assists} - K/D/A -
    -
    {m.duration}
    -
    -
    - {m.rating} -
    RATING
    -
    -
    - ))} -
    -
    -
    -
    - - {/* Footer */} -
    -
    NEXUS ARENA
    -
    - © 2024 NEXUS ARENA STUDIOS. ALL RIGHTS RESERVED. -
    -
    - {['Twitter', 'Discord', 'YouTube', 'Twitch'].map((s) => ( - {s} - ))} -
    -
    -
    - ); -} diff --git a/app/services/website/samples/interior/page.tsx b/app/services/website/samples/interior/page.tsx deleted file mode 100644 index 26f4fe2..0000000 --- a/app/services/website/samples/interior/page.tsx +++ /dev/null @@ -1,612 +0,0 @@ -'use client'; - -import Link from 'next/link'; -import { useState, useEffect } from 'react'; - -/* ══════════════════════════════════════════════ - DATA -══════════════════════════════════════════════ */ -const portfolio = [ - { title: '한남동 단독주택', cat: '주거 인테리어', area: '245㎡', img: 'https://picsum.photos/seed/interior-hannam/800/600' }, - { title: '청담 파인다이닝', cat: '상업 공간', area: '190㎡', img: 'https://picsum.photos/seed/interior-dining/800/600' }, - { title: '성수 브랜드 오피스', cat: '업무 공간', area: '380㎡', img: 'https://picsum.photos/seed/interior-office/800/600' }, - { title: '용산 아파트 리모델링', cat: '리모델링', area: '95㎡', img: 'https://picsum.photos/seed/interior-remodel/800/600' }, - { title: '강남 카페 에스프레소랩', cat: '상업 공간', area: '120㎡', img: 'https://picsum.photos/seed/interior-cafe/800/600' }, -]; - -const services = [ - { - title: '주거 인테리어', sub: 'Residential', - desc: '생활의 리듬에 맞춘 공간을 설계합니다. 단독주택부터 아파트까지, 당신의 일상이 더 아름다워지도록 모든 디테일을 손수 고릅니다.', - details: ['공간 기획 및 3D 시뮬레이션', '자재 선정 동행 서비스', '시공 전 과정 PM', '준공 후 AS 1년'], - img: 'https://picsum.photos/seed/interior-residential/800/600', - }, - { - title: '상업 공간 디자인', sub: 'Commercial', - desc: '브랜드의 철학이 공간 언어로 번역됩니다. 첫 방문객이 문을 열었을 때 느끼는 그 감정까지 설계의 범위입니다.', - details: ['브랜드 아이덴티티 반영', '동선 및 고객 UX 설계', '조명·음향 플래닝', '설비 협력사 연계'], - img: 'https://picsum.photos/seed/interior-commercial/800/600', - }, - { - title: '리모델링 & 재생', sub: 'Remodeling', - desc: '기존 공간의 가능성을 새로운 시선으로 바라봅니다. 구조적 변경부터 마감재 교체까지, 완전한 변신을 지원합니다.', - details: ['현장 실측 및 구조 분석', '철거~완공 원스톱', '예산 내 최적 시공', '친환경 자재 우선 적용'], - img: 'https://picsum.photos/seed/interior-remodeling/800/600', - }, -]; - -const testimonials = [ - { name: '하윤서', role: '한남동 단독주택 의뢰인', u: 'hayunseo', rating: 5, highlight: '계획보다 적은 예산', - text: '처음엔 예산이 걱정됐는데, 아우라 팀이 범위를 명확히 정해줘서 오히려 계획보다 적게 들었습니다. 무엇보다 완공된 공간에서 매일 아침 커피 한 잔 하는 지금이 너무 행복해요.' }, - { name: '박도현', role: '카페 에스프레소랩 대표', u: 'parkdohyun', rating: 5, highlight: '매출 340% 상승', - text: '우리 브랜드 철학을 완벽하게 공간으로 옮겨줬습니다. 오픈 첫날부터 SNS 바이럴이 터졌고, 오픈 3개월 만에 매출이 전년 대비 340% 올랐어요.' }, - { name: '이서진', role: '루미너스 COO', u: 'leeseojin', rating: 5, highlight: '직원 만족도 93점', - text: '직원들이 출근하고 싶은 공간을 만드는 게 목표였습니다. 리모델링 후 직원 만족도 설문에서 93점, 퇴직률이 절반으로 줄었습니다.' }, -]; - -const steps = [ - { num: '01', title: '무료 상담', desc: '공간 사진, 예산, 취향을 공유해 주세요. 72시간 내 맞춤 제안서를 드립니다.' }, - { num: '02', title: '콘셉트 기획', desc: '무드보드와 3D 시뮬레이션으로 완공 이후를 미리 경험합니다.' }, - { num: '03', title: '시공', desc: '전담 PM이 공정마다 현장을 점검하고 일일 리포트를 공유합니다.' }, - { num: '04', title: '준공 & AS', desc: '완공 후 1년간 무상 AS. 공간이 오래 아름답도록 함께합니다.' }, -]; - -/* ══════════════════════════════════════════════ - SVG ICONS -══════════════════════════════════════════════ */ -const StarIcon = ({ filled }: { filled: boolean }) => ( - - - -); -const CheckIcon = () => ( - - - - -); -const ArrowRight = ({ color = '#8B6914' }: { color?: string }) => ( - - - -); - -/* ══════════════════════════════════════════════ - CONSTANTS -══════════════════════════════════════════════ */ -const BANNER_H = 40; -const NAV_H = 72; - -/* ══════════════════════════════════════════════ - PAGE COMPONENT -══════════════════════════════════════════════ */ -export default function InteriorSample() { - const [scrolled, setScrolled] = useState(false); - const [showTop, setShowTop] = useState(false); - - useEffect(() => { - const scroller: HTMLElement = - (document.querySelector('.main-content') as HTMLElement | null) ?? - document.documentElement; - - const onNavScroll = () => { - setScrolled(scroller.scrollTop > 60); - setShowTop(scroller.scrollTop > 400); - }; - scroller.addEventListener('scroll', onNavScroll, { passive: true }); - - const scrollToTop = () => scroller.scrollTo({ top: 0, behavior: 'smooth' }); - const topBtn = document.getElementById('au-top-btn'); - if (topBtn) topBtn.addEventListener('click', scrollToTop); - - const observer = new IntersectionObserver( - (entries) => entries.forEach((e) => { if (e.isIntersecting) e.target.classList.add('au-visible'); }), - { threshold: 0.08, root: scroller === document.documentElement ? null : scroller } - ); - document.querySelectorAll('.au-reveal').forEach((el) => observer.observe(el)); - - return () => { - scroller.removeEventListener('scroll', onNavScroll); - if (topBtn) topBtn.removeEventListener('click', scrollToTop); - observer.disconnect(); - }; - }, []); - - const GOLD = '#8B6914'; - const DARK = '#1C1A17'; - const SAGE = '#4E5C3E'; - const CREAM = '#FAF8F5'; - const SURFACE = '#F0ECE4'; - - return ( -
    - - {/* ══ 폰트 + 전역 CSS ══ */} - - - {/* Back Banner */} -
    - - ← 홈페이지 제작 서비스로 돌아가기 - - | - - SAMPLE · 개인 포트폴리오 - -
    - - {/* Awards Marquee */} -
    -
    - {[...awards, ...awards].map((a, i) => ( -
    - - {a.name} - {a.count} -
    - ))} -
    -
    - - {/* Navbar */} - - - {/* Hero */} -
    -
    -
    - -
    -
    -
    - {'> Hello, World. I am'} -
    -

    - Kim
    - Jisu - -

    -
    - Product Designer & Creative Developer -
    -

    - 픽셀 하나하나에 의미를 담는 디자이너. 아름다움과 기능의 교차점에서 디지털 경험을 설계합니다. -

    -
    - - -
    -
    - - {/* Stats panel */} -
    - {[ - { val: '6+', label: 'YEARS EXP.', color: '#00ff88' }, - { val: '30+', label: 'PROJECTS', color: '#a855f7' }, - { val: '2×', label: 'AWWWARDS', color: '#f59e0b' }, - { val: '340%', label: 'MAX CVR LIFT', color: '#06b6d4' }, - ].map((s) => ( -
    -
    {s.val}
    -
    {s.label}
    -
    - ))} -
    -
    -
    - - {/* Services */} -
    -
    -
    -
    // WHAT I DO
    -

    - Services. -

    -
    -
    - {services.map((svc) => ( -
    -
    -
    - {svc.icon} -
    -
    {svc.title}
    -
    {svc.desc}
    -
    - ))} -
    -
    -
    - - {/* Awards Detail */} -
    -
    -
    - {awards.map((a) => ( -
    - -
    -
    {a.name}
    -
    {a.count}
    -
    -
    - ))} -
    -
    -
    - - {/* Projects */} -
    -
    -
    -
    -
    // SELECTED WORK
    -

    - Projects. -

    -
    - 2019 — 2024 -
    - {/* Category filter */} -
    - {categories.map((cat) => ( - - ))} -
    -
    - {filteredProjects.map((proj, i) => ( -
    setHoveredProject(i)} - onMouseLeave={() => setHoveredProject(null)} - style={{ border: '1px solid #111827', borderRadius: 12, overflow: 'hidden', cursor: 'pointer', background: '#0a0a0a', position: 'relative' }} - > -
    -
    -
    {proj.title}
    -
    - {/* Hover overlay */} -
    -
    {proj.desc}
    - -
    -
    - {proj.tag} -
    -
    - {proj.year} -
    -
    -
    -
    {proj.title}
    -
    {proj.desc}
    -
    -
    - ))} -
    -
    -
    - - {/* Skills + Timeline */} -
    -
    -
    -
    // EXPERTISE
    -

    - Skills. -

    -
    - {skills.map((s) => ( -
    -
    -
    - {s.name} - {s.category} -
    - {s.level}% -
    -
    -
    -
    -
    - ))} -
    -
    -
    -
    // JOURNEY
    -

    - Timeline. -

    -
    -
    - {timeline.map((t, i) => ( -
    -
    -
    {t.year}
    -
    {t.event}
    - {t.type === 'award' && ( -
    - AWARD -
    - )} -
    - ))} -
    -
    -
    -
    - - {/* Testimonials */} -
    -
    -
    // CLIENT VOICES
    -

    - Testimonials. -

    -
    - {testimonials.map((t) => ( -
    - - - -

    {t.text}

    -
    -
    - {t.client[0]} -
    -
    -
    {t.client}
    -
    {t.role}
    -
    -
    -
    - ))} -
    -
    -
    - - {/* Contact */} -
    -
    - {'> LET\'S COLLABORATE'} -
    -

    - Have a project? -

    -

    - jisu.kim@design.studio -

    -

    - @jisu_creates · Response within 24h -

    - -
    -
    - ); -} diff --git a/app/services/website/samples/reading/page.tsx b/app/services/website/samples/reading/page.tsx deleted file mode 100644 index ae91850..0000000 --- a/app/services/website/samples/reading/page.tsx +++ /dev/null @@ -1,663 +0,0 @@ -'use client'; - -import Link from 'next/link'; -import { useEffect, useRef, useState } from 'react'; - -/* ═══════════════════════════════════════ - SVG ICONS -═══════════════════════════════════════ */ -const BookOpenIcon = () => ( - - - -); -const StarIcon = ({ filled = true }: { filled?: boolean }) => ( - - - -); -const QuoteIcon = () => ( - - - -); -const CheckIcon = () => ( - - - -); -const ArrowUpRight = () => ( - - - -); -const ChevronDown = () => ( - - - -); - -/* ═══════════════════════════════════════ - COUNTUP HOOK -═══════════════════════════════════════ */ -function useCountUp(target: number, duration = 1600) { - const [count, setCount] = useState(0); - const ref = useRef(null); - - useEffect(() => { - const el = ref.current; - if (!el) return; - const obs = new IntersectionObserver( - ([entry]) => { - if (!entry.isIntersecting) return; - obs.disconnect(); - const start = performance.now(); - const tick = (now: number) => { - const elapsed = now - start; - const progress = Math.min(elapsed / duration, 1); - const ease = 1 - Math.pow(1 - progress, 3); - setCount(Math.round(target * ease)); - if (progress < 1) requestAnimationFrame(tick); - }; - requestAnimationFrame(tick); - }, - { threshold: 0.4 } - ); - obs.observe(el); - return () => obs.disconnect(); - }, [target, duration]); - - return { count, ref }; -} - -/* ═══════════════════════════════════════ - STAT ITEM -═══════════════════════════════════════ */ -function StatItem({ value, suffix, label }: { value: number; suffix?: string; label: string }) { - const { count, ref } = useCountUp(value); - return ( -
    -
    - {count} - {suffix && {suffix}} -
    -

    {label}

    -
    - ); -} - -/* ═══════════════════════════════════════ - BOOK CARD -═══════════════════════════════════════ */ -interface Book { - seed: string; title: string; author: string; rating: number; genre: string; year: number; note?: string; -} - -const books: Book[] = [ - { seed: 'book1', title: '파친코', author: '이민진', rating: 5, genre: '소설', year: 2024, note: '역사 속에 묻힌 삶의 무게를 느꼈다' }, - { seed: 'book2', title: '어린 왕자', author: '생텍쥐페리', rating: 5, genre: '고전', year: 2023 }, - { seed: 'book3', title: '원씽', author: '게리 켈러', rating: 4, genre: '자기계발', year: 2024 }, - { seed: 'book4', title: '채식주의자', author: '한강', rating: 5, genre: '소설', year: 2023, note: '불편함 속의 아름다움' }, - { seed: 'book5', title: '지능의 본질', author: '제프 호킨스', rating: 4, genre: '과학', year: 2024 }, - { seed: 'book6', title: '82년생 김지영', author: '조남주', rating: 4, genre: '소설', year: 2022 }, - { seed: 'book7', title: '노인과 바다', author: '헤밍웨이', rating: 5, genre: '고전', year: 2022 }, - { seed: 'book8', title: '생각에 관한 생각', author: '다니엘 카너먼', rating: 4, genre: '심리학', year: 2023 }, -]; - -const genreColors: Record = { - '소설': '#6B5B95', '고전': '#D4A853', '자기계발': '#4A7C59', '과학': '#2E6EA6', '심리학': '#8B4E62' -}; - -function BookCard({ book, large = false }: { book: Book; large?: boolean }) { - return ( -
    { - (e.currentTarget as HTMLElement).style.transform = 'translateY(-6px)'; - (e.currentTarget as HTMLElement).style.boxShadow = '0 20px 60px rgba(212,168,83,0.12)'; - }} - onMouseLeave={e => { - (e.currentTarget as HTMLElement).style.transform = 'translateY(0)'; - (e.currentTarget as HTMLElement).style.boxShadow = 'none'; - }} - > - {/* cover */} -
    - {book.title} -
    - {/* genre badge */} -
    {book.genre}
    - {/* rating */} -
    - {[1,2,3,4,5].map(i => )} -
    -
    - {/* info */} -
    -

    {book.author} · {book.year}

    -

    {book.title}

    - {book.note &&

    "{book.note}"

    } -
    -
    - ); -} - -/* ═══════════════════════════════════════ - MAIN PAGE -═══════════════════════════════════════ */ -export default function ReadingPage() { - const [activeGenre, setActiveGenre] = useState('전체'); - const [showTop, setShowTop] = useState(false); - - useEffect(() => { - const scroller: HTMLElement = - (document.querySelector('.main-content') as HTMLElement | null) ?? - document.documentElement; - - const onScroll = () => setShowTop(scroller.scrollTop > 400); - scroller.addEventListener('scroll', onScroll, { passive: true }); - - const obs = new IntersectionObserver( - entries => entries.forEach(e => { if (e.isIntersecting) e.target.classList.add('rd-visible'); }), - { threshold: 0.1, root: scroller === document.documentElement ? null : scroller } - ); - document.querySelectorAll('.rd-reveal').forEach(el => obs.observe(el)); - return () => { - scroller.removeEventListener('scroll', onScroll); - obs.disconnect(); - }; - }, []); - - const genres = ['전체', '소설', '고전', '자기계발', '과학', '심리학']; - const filteredBooks = activeGenre === '전체' ? books : books.filter(b => b.genre === activeGenre); - - const quotes = [ - { text: '당신이 무엇을 읽느냐가 당신이 누구인지를 말해준다. 책은 당신이 선택한 삶의 궤적이다.', author: '파친코 — 이민진', genre: '소설' }, - { text: '어른들은 숫자를 좋아한다. 새 친구 이야기를 해줄 때, 중요한 것을 절대 묻지 않는다. 그의 목소리가 어떤지, 어떤 놀이를 좋아하는지.', author: '어린 왕자 — 생텍쥐페리', genre: '고전' }, - { text: '성공한 사람들은 하나에 집중하고 나머지를 내려놓는 법을 배웠다. 한 가지를 잘하면 나머지가 따라온다.', author: '원씽 — 게리 켈러', genre: '자기계발' }, - { text: '빠른 생각은 직관이고 느린 생각은 이성이다. 우리는 대부분 빠른 생각이 옳다고 착각하며 살아간다.', author: '생각에 관한 생각 — 다니엘 카너먼', genre: '심리학' }, - ]; - - const currentlyReading = { - seed: 'current1', title: '도둑맞은 집중력', author: '요한 하리', genre: '자기계발', - progress: 67, totalPages: 380, currentPage: 255, - startDate: '2024.03.10', note: '현대 사회가 어떻게 우리의 집중력을 앗아가는지 설득력 있게 풀어냄' - }; - - const tbr = [ - { seed: 'tbr1', title: '총, 균, 쇠', author: '재레드 다이아몬드', genre: '역사', priority: '높음' }, - { seed: 'tbr2', title: '코스모스', author: '칼 세이건', genre: '과학', priority: '높음' }, - { seed: 'tbr3', title: '사피엔스', author: '유발 하라리', genre: '역사', priority: '중간' }, - ]; - - const monthlyData = [ - { month: '10월', books: 2 }, { month: '11월', books: 3 }, { month: '12월', books: 1 }, - { month: '1월', books: 4 }, { month: '2월', books: 3 }, { month: '3월', books: 2 }, - ]; - const maxBooks = Math.max(...monthlyData.map(d => d.books)); - - return ( - <> -