From c3be57ea1f389e802843cba0705b14ea640d9a94 Mon Sep 17 00:00:00 2001 From: gahusb Date: Tue, 30 Jun 2026 14:48:00 +0900 Subject: [PATCH] =?UTF-8?q?feat(redesign):=20=EC=99=B8=EC=A3=BC=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20+=20=EC=9D=98=EB=A2=B0=ED=8F=BC?= =?UTF-8?q?=20=EB=9D=BC=EC=9D=B4=ED=8A=B8=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 페이지: 다크 캔버스/HeroField/스크림 제거, surface↔surface-alt 교차 8섹션. HERO 비대칭 2단(우 FeedMock 목업). 앵커(#showcase/#portfolio/#process/#contact) 유지. 폼: --jsm-dark-* 전량 라이트 치환, jsm-dark-form 제거. 흰 카드 위 surface-alt 입력으로 가독성 확보. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01A2N6SziVSPfavx1j5rAs52 --- app/components/OutsourcingRequestForm.tsx | 72 ++-- app/outsourcing/page.tsx | 472 +++++----------------- 2 files changed, 144 insertions(+), 400 deletions(-) diff --git a/app/components/OutsourcingRequestForm.tsx b/app/components/OutsourcingRequestForm.tsx index 7af2fb6..00a2cd8 100644 --- a/app/components/OutsourcingRequestForm.tsx +++ b/app/components/OutsourcingRequestForm.tsx @@ -16,9 +16,9 @@ const KOR_TIGHT = { letterSpacing: '-0.02em' } as const; const KOR_BODY = { letterSpacing: '-0.01em' } as const; const INPUT_STYLE = { - background: 'var(--jsm-dark-surface)', - border: '1px solid var(--jsm-dark-line)', - color: 'var(--jsm-dark-ink)', + background: 'var(--jsm-surface-alt)', + border: '1px solid var(--jsm-line)', + color: 'var(--jsm-ink)', } as const; const PROJECT_TYPES = [ @@ -195,13 +195,13 @@ export default function OutsourcingRequestForm() { ref={setHeadingRef} tabIndex={-1} className="text-xl font-bold break-keep outline-none" - style={{ color: 'var(--jsm-dark-ink)', ...KOR_TIGHT }} + style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} > 의뢰가 접수되었습니다

영업일 2일 내 회신드립니다.

@@ -218,7 +218,7 @@ export default function OutsourcingRequestForm() {

추적 링크를 이메일로도 보내드렸습니다.

@@ -232,7 +232,7 @@ export default function OutsourcingRequestForm() { const canAdvance = stepValid(step); return ( -
+
{/* 진행 표시기 */}
    {STEPS.map((s, i) => { @@ -244,7 +244,7 @@ export default function OutsourcingRequestForm() { className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-bold shrink-0 transition-colors" style={ state === 'upcoming' - ? { background: 'var(--jsm-dark-surface)', color: 'var(--jsm-dark-soft)', boxShadow: 'inset 0 0 0 1px var(--jsm-dark-line)' } + ? { background: 'var(--jsm-surface-alt)', color: 'var(--jsm-ink-soft)', boxShadow: 'inset 0 0 0 1px var(--jsm-line)' } : { background: 'var(--jsm-accent)', color: '#ffffff' } } aria-current={state === 'current' ? 'step' : undefined} @@ -255,7 +255,7 @@ export default function OutsourcingRequestForm() { className="text-xs font-semibold truncate hidden sm:inline" style={{ color: - state === 'upcoming' ? 'var(--jsm-dark-soft)' : 'var(--jsm-dark-ink)', + state === 'upcoming' ? 'var(--jsm-ink-soft)' : 'var(--jsm-ink)', ...KOR_BODY, }} > @@ -264,7 +264,7 @@ export default function OutsourcingRequestForm() { {i < STEPS.length - 1 && ( )} @@ -281,13 +281,13 @@ export default function OutsourcingRequestForm() { ref={setHeadingRef} tabIndex={-1} className="text-lg font-bold break-keep outline-none mb-1" - style={{ color: 'var(--jsm-dark-ink)', ...KOR_TIGHT }} + style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} > 어떤 프로젝트인가요?

    가장 가까운 유형을 하나 선택해주세요.

    @@ -303,12 +303,12 @@ export default function OutsourcingRequestForm() { className="px-4 py-3.5 rounded-lg text-sm font-semibold text-center break-keep transition-colors outline-none focus-visible:ring-2 focus-visible:ring-[var(--jsm-accent)]" style={{ border: selected - ? '1px solid var(--jsm-accent-bright)' - : '1px solid var(--jsm-dark-line)', + ? '1px solid var(--jsm-accent)' + : '1px solid var(--jsm-line)', background: selected - ? 'rgba(96,165,250,0.12)' - : 'var(--jsm-dark-surface)', - color: selected ? 'var(--jsm-accent-bright)' : 'var(--jsm-dark-ink)', + ? 'var(--jsm-accent-soft)' + : 'var(--jsm-surface-alt)', + color: selected ? 'var(--jsm-accent)' : 'var(--jsm-ink)', ...KOR_BODY, }} > @@ -327,13 +327,13 @@ export default function OutsourcingRequestForm() { ref={setHeadingRef} tabIndex={-1} className="text-lg font-bold break-keep outline-none mb-1" - style={{ color: 'var(--jsm-dark-ink)', ...KOR_TIGHT }} + style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} > 예산과 일정을 알려주세요

    대략적인 범위면 충분합니다. 정해지지 않았다면 미정을 선택하세요.

    @@ -341,7 +341,7 @@ export default function OutsourcingRequestForm() {
    예산 @@ -360,7 +360,7 @@ export default function OutsourcingRequestForm() {
    희망 일정 @@ -385,13 +385,13 @@ export default function OutsourcingRequestForm() { ref={setHeadingRef} tabIndex={-1} className="text-lg font-bold break-keep outline-none mb-1" - style={{ color: 'var(--jsm-dark-ink)', ...KOR_TIGHT }} + style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} > 자세히 들려주세요

    구체적일수록 정확한 견적이 가능합니다. 최소 10자 이상 작성해주세요.

    @@ -413,7 +413,7 @@ export default function OutsourcingRequestForm() { />

    {trimmedMessage.length}/10자 이상

    @@ -427,13 +427,13 @@ export default function OutsourcingRequestForm() { ref={setHeadingRef} tabIndex={-1} className="text-lg font-bold break-keep outline-none mb-1" - style={{ color: 'var(--jsm-dark-ink)', ...KOR_TIGHT }} + style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} > 어디로 회신드릴까요?

    영업일 2일 내에 회신드립니다.

    @@ -443,7 +443,7 @@ export default function OutsourcingRequestForm() { @@ -465,7 +465,7 @@ export default function OutsourcingRequestForm() { @@ -487,7 +487,7 @@ export default function OutsourcingRequestForm() { @@ -530,10 +530,10 @@ export default function OutsourcingRequestForm() { type="button" onClick={goPrev} disabled={submitting} - className="px-5 py-3 rounded-lg text-sm font-semibold border transition-colors hover:bg-[var(--jsm-dark-surface)] disabled:opacity-50 disabled:cursor-not-allowed" + className="px-5 py-3 rounded-lg text-sm font-semibold border transition-colors hover:bg-[var(--jsm-surface-alt)] disabled:opacity-50 disabled:cursor-not-allowed" style={{ ...INPUT_STYLE, - borderColor: 'var(--jsm-dark-line)', + borderColor: 'var(--jsm-line)', ...KOR_BODY, }} > @@ -548,7 +548,7 @@ export default function OutsourcingRequestForm() { className="flex-1 py-3 rounded-lg text-sm font-semibold text-white transition-colors" style={{ background: !canAdvance || submitting - ? 'var(--jsm-dark-line)' + ? 'var(--jsm-line)' : 'var(--jsm-accent)', cursor: !canAdvance || submitting ? 'not-allowed' : 'pointer', ...KOR_BODY, @@ -563,7 +563,7 @@ export default function OutsourcingRequestForm() { disabled={!canAdvance} className="flex-1 inline-flex items-center justify-center gap-2 py-3 rounded-lg text-sm font-semibold text-white transition-colors" style={{ - background: canAdvance ? 'var(--jsm-accent)' : 'var(--jsm-dark-line)', + background: canAdvance ? 'var(--jsm-accent)' : 'var(--jsm-line)', cursor: canAdvance ? 'pointer' : 'not-allowed', ...KOR_BODY, }} @@ -595,9 +595,9 @@ function Chip({ aria-pressed={selected} className="px-4 py-2.5 rounded-lg text-sm font-semibold break-keep transition-colors outline-none focus-visible:ring-2 focus-visible:ring-[var(--jsm-accent)]" style={{ - border: selected ? '1px solid var(--jsm-accent-bright)' : '1px solid var(--jsm-dark-line)', - background: selected ? 'rgba(96,165,250,0.12)' : 'var(--jsm-dark-surface)', - color: selected ? 'var(--jsm-accent-bright)' : 'var(--jsm-dark-ink)', + border: selected ? '1px solid var(--jsm-accent)' : '1px solid var(--jsm-line)', + background: selected ? 'var(--jsm-accent-soft)' : 'var(--jsm-surface-alt)', + color: selected ? 'var(--jsm-accent)' : 'var(--jsm-ink)', ...KOR_BODY, }} > diff --git a/app/outsourcing/page.tsx b/app/outsourcing/page.tsx index fab99fb..ddcb8a8 100644 --- a/app/outsourcing/page.tsx +++ b/app/outsourcing/page.tsx @@ -2,15 +2,15 @@ import Link from 'next/link'; import type { Metadata } from 'next'; import OutsourcingRequestForm from '@/app/components/OutsourcingRequestForm'; -import HeroField from '@/app/components/deepfield/HeroField'; import ShowcaseGrid from '@/app/components/deepfield/ShowcaseGrid'; import ScrollReveal from '@/app/components/deepfield/ScrollReveal'; +import MockWindow from '@/app/components/mock/MockWindow'; +import { FeedMock } from '@/app/components/mock/screens'; import { SHOWCASE_SLOTS } from '@/lib/showcase'; -// 외주 개발 의뢰 페이지 (서버 컴포넌트) — Deep Field 다크 캔버스. -// PublicShell이 TopNav(h-16, /outsourcing 다크 인지)·푸터·main 배경(라이트)을 제공한다. -// 이 페이지는 자기 풀-블리드 다크 배경을 소유해 main의 라이트 배경을 덮고, -// 메인(/)과 동일한 비주얼 언어(다크 루트 div + -mt-16 hero + 섹션 border-t 리듬 + 모노 라벨 헤더)를 따른다. +// 외주 개발 의뢰 페이지 (서버 컴포넌트) — 라이트 고craft. +// PublicShell의 단일 라이트 셸을 따르며, 메인(/)과 동일한 비주얼 언어 +// (surface↔surface-alt 교차 + accent 모노 라벨 헤더 + 카드 스펙)를 공유한다. export const metadata: Metadata = { title: '외주 개발', @@ -22,30 +22,12 @@ const KOR_TIGHT = { letterSpacing: '-0.02em' } as const; const KOR_BODY = { letterSpacing: '-0.01em' } as const; const FIELDS = [ - { - t: '웹 서비스 개발', - d: '회원·결제·관리자까지, 실제로 굴러가는 서비스를 기획부터 배포까지 만들어 드립니다.', - }, - { - t: '웹사이트 제작', - d: '기업 소개·포트폴리오·랜딩 페이지를 반응형·SEO까지 갖춰 제작합니다.', - }, - { - t: '업무 자동화', - d: 'RPA·엑셀 집계·웹 크롤링으로 반복 업무를 사람 손에서 떼어냅니다.', - }, - { - t: 'API·백엔드', - d: '데이터 모델 설계부터 인증·외부 연동까지 안정적인 서버를 구축합니다.', - }, - { - t: '텔레그램·디스코드 봇', - d: '알림·명령·자동 응답 봇으로 운영과 커뮤니티 관리를 자동화합니다.', - }, - { - t: 'AI 연동 개발', - d: 'LLM·생성형 AI를 업무 흐름에 붙여 초안 작성·분류·요약을 자동화합니다.', - }, + { t: '웹 서비스 개발', d: '회원·결제·관리자까지, 실제로 굴러가는 서비스를 기획부터 배포까지 만들어 드립니다.' }, + { t: '웹사이트 제작', d: '기업 소개·포트폴리오·랜딩 페이지를 반응형·SEO까지 갖춰 제작합니다.' }, + { t: '업무 자동화', d: 'RPA·엑셀 집계·웹 크롤링으로 반복 업무를 사람 손에서 떼어냅니다.' }, + { t: 'API·백엔드', d: '데이터 모델 설계부터 인증·외부 연동까지 안정적인 서버를 구축합니다.' }, + { t: '텔레그램·디스코드 봇', d: '알림·명령·자동 응답 봇으로 운영과 커뮤니티 관리를 자동화합니다.' }, + { t: 'AI 연동 개발', d: 'LLM·생성형 AI를 업무 흐름에 붙여 초안 작성·분류·요약을 자동화합니다.' }, ]; const PROCESS = [ @@ -57,143 +39,66 @@ const PROCESS = [ { n: '06', t: '무상 하자보수 30일', d: '납품 후 30일간 결함·수정을 무상으로 대응해 안정화까지 책임집니다.' }, ]; -// 기존 work/freelance(lib/freelance-portfolio) 실사례를 다크 토큰 기준으로 재구성. const CASES = [ - { - t: '주식 자동매매 시스템', - cat: '실시간 트레이딩 · 직접 운영 중', - live: true, - d: '텔레그램과 연동해 실시간으로 주문을 집행하고 체결·손익 리포트를 자동 전송합니다.', - tags: ['Python', 'Telegram Bot', '실시간 주문'], - }, - { - t: '부동산 청약 자동 수집·매칭', - cat: '크롤링 · 직접 운영 중', - live: true, - d: '공고를 주기적으로 크롤링해 조건에 맞는 매물만 골라내고, 신규 매칭을 즉시 푸시합니다.', - tags: ['Python', '크롤링', '조건 매칭'], - }, - { - t: 'AI 콘텐츠 자동화 파이프라인', - cat: 'AI 연동 · 직접 운영 중', - live: true, - d: '생성부터 검수, 발행까지 사람이 개입할 지점만 남기고 전 과정을 자동으로 연결합니다.', - tags: ['AI 연동', '검수 워크플로우', '자동 발행'], - }, - { - t: 'Gmail 자동화 RPA', - cat: 'RPA · 납품 완료', - live: false, - d: '거래처 이메일 수신 시 자동 분류, 답장 초안 작성, 담당자 알림을 전송합니다.', - tags: ['Python', 'Gmail API'], - }, - { - t: '쇼핑몰 가격 모니터링 봇', - cat: '웹 스크래핑 · 납품 완료', - live: false, - d: '경쟁사 상품 가격을 매일 모니터링해 변동 시 텔레그램으로 즉시 알립니다.', - tags: ['Python', 'Selenium', 'Telegram Bot'], - }, - { - t: '영업 일보 자동화 시스템', - cat: '엑셀 자동화 · 납품 완료', - live: false, - d: '엑셀 데이터를 자동 집계해 일·주·월별 보고서 PDF를 생성하고 매일 09시 발송합니다.', - tags: ['Python', 'OpenPyXL', 'ReportLab'], - }, + { t: '주식 자동매매 시스템', cat: '실시간 트레이딩 · 직접 운영 중', live: true, d: '텔레그램과 연동해 실시간으로 주문을 집행하고 체결·손익 리포트를 자동 전송합니다.', tags: ['Python', 'Telegram Bot', '실시간 주문'] }, + { t: '부동산 청약 자동 수집·매칭', cat: '크롤링 · 직접 운영 중', live: true, d: '공고를 주기적으로 크롤링해 조건에 맞는 매물만 골라내고, 신규 매칭을 즉시 푸시합니다.', tags: ['Python', '크롤링', '조건 매칭'] }, + { t: 'AI 콘텐츠 자동화 파이프라인', cat: 'AI 연동 · 직접 운영 중', live: true, d: '생성부터 검수, 발행까지 사람이 개입할 지점만 남기고 전 과정을 자동으로 연결합니다.', tags: ['AI 연동', '검수 워크플로우', '자동 발행'] }, + { t: 'Gmail 자동화 RPA', cat: 'RPA · 납품 완료', live: false, d: '거래처 이메일 수신 시 자동 분류, 답장 초안 작성, 담당자 알림을 전송합니다.', tags: ['Python', 'Gmail API'] }, + { t: '쇼핑몰 가격 모니터링 봇', cat: '웹 스크래핑 · 납품 완료', live: false, d: '경쟁사 상품 가격을 매일 모니터링해 변동 시 텔레그램으로 즉시 알립니다.', tags: ['Python', 'Selenium', 'Telegram Bot'] }, + { t: '영업 일보 자동화 시스템', cat: '엑셀 자동화 · 납품 완료', live: false, d: '엑셀 데이터를 자동 집계해 일·주·월별 보고서 PDF를 생성하고 매일 09시 발송합니다.', tags: ['Python', 'OpenPyXL', 'ReportLab'] }, ]; const FAQ = [ - { - q: '견적은 어떻게 산정되나요?', - a: '기능 범위와 구현 난이도를 기준으로 산정합니다. 상담에서 필요한 기능을 함께 정리한 뒤, 영업일 2일 내에 범위·일정·금액을 명시한 견적으로 회신드립니다. 추측으로 부풀리지 않고 실제 작업량 기준으로 잡습니다.', - }, - { - q: '수정 요청은 몇 번까지 가능한가요?', - a: '합의한 범위 안에서는 2회까지 무상으로 수정해 드립니다. 범위를 벗어나는 기능 추가나 방향 전환은 별도로 협의해 진행합니다. 무엇이 범위 안/밖인지는 착수 전 견적에 미리 명시합니다.', - }, - { - q: '소스코드도 제공되나요?', - a: '제공됩니다. 잔금 완납 시 전체 소스코드와 배포·실행 문서를 함께 전달합니다. 직접 운영하시거나 다른 개발자에게 이어 맡기셔도 문제없도록 인도합니다.', - }, - { - q: '납품 후 유지보수는요?', - a: '납품일로부터 30일간 결함·오류를 무상으로 하자보수합니다. 이후 기능 추가나 지속 운영이 필요하면 월 단위 유지보수 계약으로 이어갈 수 있습니다.', - }, + { q: '견적은 어떻게 산정되나요?', a: '기능 범위와 구현 난이도를 기준으로 산정합니다. 상담에서 필요한 기능을 함께 정리한 뒤, 영업일 2일 내에 범위·일정·금액을 명시한 견적으로 회신드립니다. 추측으로 부풀리지 않고 실제 작업량 기준으로 잡습니다.' }, + { q: '수정 요청은 몇 번까지 가능한가요?', a: '합의한 범위 안에서는 2회까지 무상으로 수정해 드립니다. 범위를 벗어나는 기능 추가나 방향 전환은 별도로 협의해 진행합니다. 무엇이 범위 안/밖인지는 착수 전 견적에 미리 명시합니다.' }, + { q: '소스코드도 제공되나요?', a: '제공됩니다. 잔금 완납 시 전체 소스코드와 배포·실행 문서를 함께 전달합니다. 직접 운영하시거나 다른 개발자에게 이어 맡기셔도 문제없도록 인도합니다.' }, + { q: '납품 후 유지보수는요?', a: '납품일로부터 30일간 결함·오류를 무상으로 하자보수합니다. 이후 기능 추가나 지속 운영이 필요하면 월 단위 유지보수 계약으로 이어갈 수 있습니다.' }, ]; function ArrowRight() { return ( - + ); } +function Eyebrow({ children }: { children: React.ReactNode }) { + return ( +

    + {children} +

    + ); +} + export default function OutsourcingPage() { return ( - // 풀-블리드 다크 캔버스 — main의 라이트 배경을 덮는다. -
    - {/* ─────────────────── 1. HERO (축약 ~60vh) ─────────────────── */} - {/* -mt-16 pt-16: 고정 헤더 아래로 끌어올려 상단 라이트 띠 제거 */} -
    - - {/* 콘텐츠 가독성용 스크림 (radial 광원 위 텍스트 대비) */} -
    -
    -
    - - + <> + {/* ─────────────────── 1. HERO ─────────────────── */} +
    +
    +
    + + outsourcing

    맞춤 소프트웨어
    외주 개발 - . + .

    -

    +

    기획 정리가 안 됐어도 괜찮습니다. 상담에서 함께 정리합니다.

    -
    +
    의뢰 내용 보내기 @@ -201,119 +106,72 @@ export default function OutsourcingPage() { 작업 화면 보기
    + +
    + + + +
    {/* ─────────────────── 2. SHOWCASE (풀 그리드) ─────────────────── */} -
    - {/* 하위 호환: 기존 /outsourcing#portfolio 링크(메인 footer 등)용 앵커 유지 */} +
    + {/* 하위 호환: 기존 /outsourcing#portfolio 링크 앵커 유지 */}
    -
    +
    -

    - showcase -

    -

    + showcase +

    우리가 만드는 화면들

    - -
    +
    {/* ─────────────────── 3. 운영 실사례 ─────────────────── */} -
    -
    +
    +
    -

    - in production -

    -

    + in production +

    직접 개발하고, 실제로 굴러가는 결과물

    -

    +

    운영 중인 서비스와 납품 완료 프로젝트입니다. 의뢰하신 프로젝트도 같은 깊이로 만듭니다.

    -
    +
    {CASES.map((c, i) => ( -
    +
    - {c.live && ( - - )} + {c.live && } {c.cat} -

    +

    {c.t}

    -

    +

    {c.d}

    {c.tags.map((tag) => ( - + {tag} ))} @@ -326,43 +184,23 @@ export default function OutsourcingPage() {
    {/* ─────────────────── 4a. 제공 분야 ─────────────────── */} -
    -
    +
    +
    -

    - scope -

    -

    + scope +

    이런 것들을 만들어 드립니다

    -
    +
    {FIELDS.map((f, i) => ( -
    -

    +
    +

    {f.t}

    -

    +

    {f.d}

    @@ -373,53 +211,29 @@ export default function OutsourcingPage() {

    {/* ─────────────────── 4b. 진행 프로세스 ─────────────────── */} -
    -
    +
    +
    -

    - process -

    -

    + process +

    상담부터 하자보수까지, 흐름이 분명합니다

    -
    +
    {PROCESS.map((s, i) => ( -
    +
    {s.n} -

    +

    {s.t}

    -

    +

    {s.d}

    @@ -430,57 +244,26 @@ export default function OutsourcingPage() {
    {/* ─────────────────── 5. FAQ ─────────────────── */} -
    -
    +
    +
    -

    - faq -

    -

    + faq +

    자주 묻는 질문

    -
    +
    {FAQ.map((item, i) => ( -
    - +
    + {item.q} - + -

    +

    {item.a}

    @@ -491,59 +274,26 @@ export default function OutsourcingPage() {
    {/* ─────────────────── 6. 의뢰 폼 ─────────────────── */} -
    -
    +
    +
    {/* 안내 */}
    -

    - contact -

    -

    + contact +

    프로젝트 문의

    -

    - 영업일 2일 내에 회신드립니다. 아이디어 단계여도 괜찮습니다 — 상담에서 방향을 - 함께 잡아드립니다. +

    + 영업일 2일 내에 회신드립니다. 아이디어 단계여도 괜찮습니다 — 상담에서 방향을 함께 잡아드립니다.

    -
    - - - Mail - + @@ -553,13 +303,7 @@ export default function OutsourcingPage() { {/* 폼 */}
    -
    +
    @@ -567,6 +311,6 @@ export default function OutsourcingPage() {
    -
    + ); }