o2o-castad-frontend/src/components/pipelineIcons.tsx
Haewon Kam 0ca2140b98 feat: 썰박스 DS 통일과 Poster to Video 통합, 진입 화면 네비게이션 개편
썰박스를 ADO2 디자인 시스템으로 맞추고, 포스터 파이프라인 두 종을 파이프라인
탭에 추가한다. 탭이 4개가 되면서 진입 화면 네비게이션도 함께 손봤다.

## 썰박스 DS 통일
시나리오별 팔레트(조선=파랑·삼국지=빨강·그리스=녹·오디세이=청)와 이모지, 앰버
강조색(--color-ssul-accent)을 걷어냈다. 선택 표시는 castad 표준 문법(민트 테두리
+ 민트 틴트), 스피너는 퍼플, CTA는 퍼플 단색으로 통일했다. 색으로 구분하던 것을
없앤 대신 상태(선택)만 색으로 남긴다.

## Poster to Video 통합 (내부 시연 범위)
- 무빙 포스터(F1): 업로드 → 분석 → **검수 게이트** → 생성 → 완성 5단계 위저드.
  검수에서 나레이션·모션·메타태그를 포스터와 대조해 고치고 승인해야 렌더가 이어진다.
- 포스터 스타일링(F2): 위저드가 아닌 한 화면 도구. 여러 스타일을 갈아 끼우며
  비교하는 작업이라 단계를 나누면 왕복만 늘어난다.

P2V 서버(:8010)를 castad 백엔드가 아니라 **직접 호출**한다. 검증된 scripts를
subprocess로 감싼 단일 워커라 castad 백엔드에 흡수하려면 실행 환경(Higgsfield
CLI·ffmpeg·모델 키)을 통째로 이식해야 하기 때문이다. 호출은 utils/p2vApi.ts 한
파일에 격리했다 — 대외 공개 시 castad 백엔드에 /p2v/* 프록시를 세우고 카카오 인증·
크레딧 차감을 얹을 때 갈아끼울 지점이 여기 하나다.

인증은 단일 팀 키(P2V_ACCESS_KEY)다. 다른 오리진이라 쿠키가 실리지 않아 정적
산출물(영상·이미지·다운로드)은 p2vFile()이 ?key= 로 태운다.

F2는 영화 포스터 레퍼런스가 저작권 자산이라 **결과물의 외부 공개·상업 사용을
금한다**(퍼블릭 도메인 명화 제외). 화면 상단 고지 + 템플릿별 배포 등급 배지 +
내부 전용을 고른 순간에만 뜨는 경고로 표시한다.

## 진입 화면 네비게이션
- 밑줄 탭 → 아이콘 타일 + 기능명. 탭이 4개가 되자 "무빙 포스터"와 "포스터 스타일링"이
  글자로는 갈라지지 않아, 형태로 구분되게 했다. 아이콘은 ADO2 Design System 규칙
  (24×24 · fill none · stroke currentColor 2 · round)을 따르고 색은 넣지 않는다.
- 고른 기능의 한 줄 설명을 탭 아래에 붙였다.
- 간격 체계를 8px 그리드로 다시 잡았다(묶음 안 8~12 / 묶음 사이 20 / 섹션 28~32).
  이전에는 전부 10~24px이라 근접성으로 구조가 읽히지 않아 답답했다. 타일 간격은
  터치 타겟 최소 8dp를 지킨다.

## 버그 수정
- 진입 화면 세로 넘침 잘림: justify-content:center + overflow:hidden 조합이라
  콘텐츠가 길어지면 위로 넘친 부분에 스크롤로도 닿을 수 없었다(무빙 포스터에서
  로고 밴드 47px 잘림). 자식의 margin:auto 0 중앙정렬로 바꿔 해소.
- 사라진 P2V 잡: 404를 문구가 아니라 상태 코드로 판정한다(P2vNotFoundError).
  서버에서 지워진 잡 ID가 남으면 빈 진행 화면에서 멈췄다.
- 검수 화면 모바일: 좌우 여백 0(부모 위저드 컨테이너에 패딩이 없다) → 16px 부여.
  대조할 포스터를 편집 위로 올리고, 승인 CTA를 하단 탭바 위에 sticky로 고정.
- 한글 단어 중간 줄바꿈("애니메이/션") → word-break: keep-all.
- 입력·안내·제출 박스 높이를 48px로 통일.

## 카피
가게→업체, 크롤링→수집으로 어휘 통일.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 12:55:06 +09:00

70 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from 'react';
/**
* 파이프라인 타일 아이콘.
*
* ADO2 Design System 의 아이콘 규칙을 그대로 따른다(`assets/icons/*.svg`):
* viewBox 24×24 · fill none · stroke currentColor · stroke-width 2 · round cap/join
*
* 색은 넣지 않는다 — currentColor 로 두고 타일이 상태(민트/회색)를 정한다.
* 파이프라인마다 다른 색을 주면 ADO2 팔레트(민트 액센트 + 퍼플 CTA 한 곳)가 깨진다.
* 구분은 **형태**로만 한다.
*/
interface IconProps {
size?: number;
}
const base = (size: number) => ({
width: size,
height: size,
viewBox: '0 0 24 24',
fill: 'none',
stroke: 'currentColor',
strokeWidth: 2,
strokeLinecap: 'round' as const,
strokeLinejoin: 'round' as const,
});
/** ADO2 — 업체(가게)를 분석해 콘텐츠를 만든다 → 상점 차양 */
export const StorefrontIcon: React.FC<IconProps> = ({ size = 24 }) => (
<svg {...base(size)} aria-hidden="true">
<path d="M4 10v9a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-9" />
<path d="M3 10l1.4-4.3A1 1 0 0 1 5.35 5h13.3a1 1 0 0 1 .95.7L21 10a2.5 2.5 0 0 1-4.5 1.5A2.5 2.5 0 0 1 12 11.4a2.5 2.5 0 0 1-4.5.1A2.5 2.5 0 0 1 3 10z" />
<path d="M10 20v-5h4v5" />
</svg>
);
/** 썰박스 — 역사 이야기 → 펼친 책 */
export const BookIcon: React.FC<IconProps> = ({ size = 24 }) => (
<svg {...base(size)} aria-hidden="true">
<path d="M12 7.5v12" />
<path d="M3 5h5a4 4 0 0 1 4 2.5V19.5A3 3 0 0 0 9.5 18H3V5z" />
<path d="M21 5h-5a4 4 0 0 0-4 2.5V19.5A3 3 0 0 1 14.5 18H21V5z" />
</svg>
);
/**
* 무빙 포스터 — 포스터가 영상이 된다 → 세로 포스터 + 재생.
*
* 프레임은 2:3 세로다(12×18). 가로 프레임으로 그리면 일반 '동영상' 아이콘과
* 구별되지 않는다 — 소재가 **포스터**라는 점이 이 기능의 정체성이라 비율로 드러낸다.
*/
export const PosterVideoIcon: React.FC<IconProps> = ({ size = 24 }) => (
<svg {...base(size)} aria-hidden="true">
<rect x="6" y="3" width="12" height="18" rx="2" />
{/* 재생 삼각형만 채운다 — 아웃라인으로 그리면 이 크기에서 뭉개진다 */}
<path d="M10.5 9v6l4.2-3z" fill="currentColor" />
</svg>
);
/** 포스터 스타일 — 화풍 재해석 → 팔레트 */
export const PaletteIcon: React.FC<IconProps> = ({ size = 24 }) => (
<svg {...base(size)} aria-hidden="true">
<path d="M12 3a9 9 0 1 0 0 18 1.8 1.8 0 0 0 1.35-3 1.8 1.8 0 0 1 1.35-3H17a4 4 0 0 0 4-4c0-4.42-4.03-8-9-8z" />
<circle cx="7.6" cy="12.4" r="1.1" fill="currentColor" stroke="none" />
<circle cx="9.8" cy="8.2" r="1.1" fill="currentColor" stroke="none" />
<circle cx="14.6" cy="7.6" r="1.1" fill="currentColor" stroke="none" />
</svg>
);