Files
C.E.L_Slide_test2/PHASE-FIGMA-BLOCKS.md
kyeongmin 05703c8e72 WIP: hero-icon-cards_1 블록 + 오답노트 + figma 관련 파일
- hero-icon-cards_1.html: hero-icon-cards 변형 (icon → 소제목+불릿 계층)
- compare-detail-gradient.html: 하단 2열 비교 블록 (Figma Frame 4 기반)
- 오답노트.md: 절대 하지 말아야 하는 실수 목록
- figma_to_html.py: Figma→HTML 변환 스크립트
- static/figma-assets/: Figma export 이미지 (배지, 화살표)
- 주의: compare-detail-gradient CSS 폰트 크기가 임의 수정됨 — 원본 복원 필요

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 17:14:09 +09:00

464 lines
16 KiB
Markdown
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.
# Phase 2: Figma Block Design Specification
> 3개 블록 + 2개 서브 컴포넌트 상세 설계
> 기준: FIGMA-DESIGN-LANGUAGE.md 분석 결과
---
## Block 1: `hero-icon-cards`
### 1.1 시각적 구조
```
┌──────────────────────────────────────────────┐
│ [Hero Statement - 큰 텍스트, 중앙] │ ← zone: header or full-width
│ │
│ ┌─[Badge Title]─┐ │
│──────────┤ ├───────────────────│
│ ┌─────┐ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │icon │ │ │icon │ │icon │ │icon │ │icon │ │ ← N개 카드 (2~6)
│ │ │ │ │ │ │ │ │ │ │ │ │
│ │Title│ ╎ │Title│ │Title│ │Title│ │Title│ │ ← 세로 구분선
│ │(sub)│ │ │(sub)│ │(sub)│ │(sub)│ │(sub)│ │
│ └─────┘ │ └─────┘ └─────┘ └─────┘ └─────┘ │
│ └───────────────────────────────────│
└──────────────────────────────────────────────┘
```
### 1.2 슬롯 정의
| 슬롯 | 필수 | 타입 | 설명 |
|------|------|------|------|
| `statement` | O | string | Hero 메시지 (1-2줄) |
| `badge_title` | X | string | 배지 바 텍스트 |
| `cards[]` | O | array | 카드 배열 |
| `cards[].icon` | X | string | 아이콘 이미지 URL 또는 이모지 |
| `cards[].title` | O | string | 영문 또는 주제목 |
| `cards[].subtitle` | X | string | 한국어 부제 |
| `cards[].color` | X | string | 개별 카드 강조색 |
### 1.3 동적 재구성 규칙
#### 그리드 계산
```
입력: N = cards.length, W = container_width_px
N ≤ 5: 1행 N열
col_count = N
card_width = (W - padding*2 - gap*(N-1)) / N
N = 6: 1행 6열 (gap 축소)
col_count = 6
gap = 8px (기본 16px에서 축소)
N > 6: 2행
col_count = ceil(N / 2)
row_count = 2
```
#### 폰트 스케일링
```
card_width ≥ 200px → title: 20px, subtitle: 14px
card_width ≥ 150px → title: 16px, subtitle: 12px
card_width < 150px → title: 14px, subtitle: 11px
```
#### 높이 계산
```
hero_height = statement_lines * line_height + padding
badge_height = 44px (고정)
card_area_height = icon_height + title_lines * title_lh + subtitle_lh + padding
- 1행: card_area_height
- 2행: card_area_height * 2 + gap
total_min_height = hero_height + badge_height + card_area_height + gaps
```
### 1.4 catalog.yaml schema
```yaml
- id: hero-icon-cards
name: 히어로 문구 + 아이콘 카드
category: cards
template: blocks/cards/hero-icon-cards.html
height_cost: xlarge
min_height_px: 280
relation_types: [definition, flow]
min_items: 2
max_items: 6
visual: >
상단에 큰 Hero 메시지(24px bold, 중앙) + 배지 바 +
하단에 N열 아이콘 카드(둥근 흰색 컨테이너, 세로 구분선).
각 카드는 아이콘 이미지 + 영문 제목(20px/900) + 한국어 부제(14px/500).
when: >
핵심 목표나 가치를 N개 키워드로 선언할 때.
각 키워드에 아이콘이나 이미지가 있을 때.
"우리가 추구하는 5가지 가치" 같은 구조.
not_for: >
비교/대조 구조 → compare-2col-badge.
상세 설명이 길 때 → card-icon-desc.
순서/단계 → card-step-vertical 또는 process-horizontal.
purpose_fit: [핵심전달, 가치선언]
zone: full-width-only
slots:
required: [statement, cards[]]
optional: [badge_title, cards[].icon, cards[].subtitle, cards[].color]
schema:
statement:
max_lines: 2
font_size: 24
ref_chars:
body: 60
note: "24px bold, 중앙정렬, 흰색 스트로크"
badge_title:
max_lines: 1
font_size: 18
ref_chars:
body: 20
note: "18px bold white, 배지 바 위"
card_title:
max_lines: 2
font_size: 20
ref_chars:
body: 15
note: "20px black/900, 중앙정렬"
card_subtitle:
max_lines: 1
font_size: 14
ref_chars:
body: 10
note: "14px medium, 한국어 부제"
padding_overhead_px: 60
padding_h_px: 32
```
---
## Block 2: `compare-2col-badge`
### 2.1 시각적 구조
```
┌──────────────────────────────────────────────┐
│ ┌─[Badge Title]─┐ │
│────────────┤ ├─────────────────│
│ │
│ ┌── Left Column ──┐ ╎ ┌── Right Column ──┐ │
│ │ │ ╎ │ │ │
│ │ [Big Title] │ ╎ │ [Big Title] │ │
│ │ │ ╎ │ │ │
│ │ body text... │ ╎ │ body text... │ │
│ │ body text... │ ╎ │ body text... │ │
│ │ │ ╎ │ │ │
│ └──────────────────┘ ╎ └──────────────────┘ │
│ │
│ [Optional: Hero Statement] │
└──────────────────────────────────────────────┘
```
### 2.2 슬롯 정의
| 슬롯 | 필수 | 타입 | 설명 |
|------|------|------|------|
| `badge_title` | O | string | 배지 바 텍스트 |
| `left_title` | O | string | 좌측 열 대제목 |
| `left_body` | O | string | 좌측 열 본문 |
| `right_title` | O | string | 우측 열 대제목 |
| `right_body` | O | string | 우측 열 본문 |
| `statement` | X | string | 하단 Hero 메시지 |
| `left_color` | X | string | 좌측 강조색 (기본: --color-teal) |
| `right_color` | X | string | 우측 강조색 (기본: --color-teal) |
### 2.3 동적 재구성 규칙
#### 레이아웃 계산
```
container_width = 컨테이너 전체 폭
padding_h = 32px * 2
2열 모드 (기본):
col_width = (container_width - padding_h - divider_gap) / 2
divider_gap = 32px
1열 모드 (sidebar zone, 폭 < 500px):
좌/우가 세로 스택
col_width = container_width - padding_h
```
#### 높이 계산
```
badge_height = 44px
left_height = title_height + body_lines * line_height + padding
right_height = title_height + body_lines * line_height + padding
content_height = max(left_height, right_height)
statement_height = statement ? (statement_lines * 28 + 16) : 0
total = badge_height + content_height + statement_height + gaps
```
#### 텍스트 피팅
```
col_width에 따른 body 글자수 제한:
col_width ≥ 500px → ~40자/줄, font: 16px
col_width ≥ 350px → ~28자/줄, font: 14px
col_width < 350px → ~20자/줄, font: 13px
```
### 2.4 catalog.yaml schema
```yaml
- id: compare-2col-badge
name: 배지 헤더 2열 비교
category: cards
template: blocks/cards/compare-2col-badge.html
height_cost: large
min_height_px: 200
relation_types: [comparison, contrast]
visual: >
상단 배지 바(이미지/그라디언트 배경 + 흰색 텍스트) 아래
2열 비교 레이아웃. 좌/우 각각 대제목(24px/900) + 본문(16px/700).
중앙 세로 구분선. 둥근 흰색 컨테이너(r:20).
선택적 하단 Hero 메시지.
when: >
두 개념/방법/전략을 나란히 비교할 때.
배지 헤더로 상위 주제를 명시.
예: "Engn. Solution vs DfMA", "현재 vs 미래"
not_for: >
3개 이상 항목 비교 → compare-3col-badge.
장/단점 목록 → comparison-2col.
상세 내용이 길고 섹션이 많을 때 → compare-detail-gradient.
purpose_fit: [비교대조, 개념정의]
zone: full-width-only
slots:
required: [badge_title, left_title, left_body, right_title, right_body]
optional: [statement, left_color, right_color]
schema:
badge_title:
max_lines: 1
font_size: 18
ref_chars:
body: 15
note: "18px bold white, 배지 바"
left_title:
max_lines: 1
font_size: 24
ref_chars:
body: 15
note: "24px black/900, 흰색 스트로크"
left_body:
max_lines: 6
font_size: 16
ref_chars:
body: 200
note: "16px/700, 틸 색상"
right_title:
max_lines: 1
font_size: 24
ref_chars:
body: 15
note: "24px black/900, 흰색 스트로크"
right_body:
max_lines: 6
font_size: 16
ref_chars:
body: 200
note: "16px/700, 틸 색상"
statement:
max_lines: 2
font_size: 20
ref_chars:
body: 50
note: "20px bold, 중앙정렬"
padding_overhead_px: 56
padding_h_px: 32
```
---
## Block 3: `compare-detail-gradient`
### 3.1 시각적 구조
```
┌──────────────────────────────────────────────────────────┐
│ ┌───── Left Header Bar (gradient) ─────┐┌── Right ─────┐│
│ │ [Left Column Title] ││ [Right Title] ││
│ └──────────────────────────────────────┘└───────────────┘│
│ ┌─────── Left BG (warm) ──────┐┌──── Right BG (teal) ──┐│
│ │ ││ ││
│ │ [Section 1 Title] ││ [Section 1 Title] ││
│ │ • body text ││ • body text ││
│ │ • body text ││ • body text ││
│ │ ││ ││
│ │ [Section 2 Title] ││ [Section 2 Title] ││
│ │ • body text ││ • body text ││
│ │ • body text ││ • body text ││
│ │ ││ ││
│ │ [Section N Title] ││ [Section M Title] ││
│ │ • body text ││ • body text ││
│ └──────────────────────────────┘└───────────────────────┘│
└──────────────────────────────────────────────────────────┘
```
### 3.2 슬롯 정의
| 슬롯 | 필수 | 타입 | 설명 |
|------|------|------|------|
| `left_header` | O | string | 좌측 열 헤더 타이틀 |
| `right_header` | O | string | 우측 열 헤더 타이틀 |
| `left_sections[]` | O | array | 좌측 섹션 배열 |
| `left_sections[].title` | O | string | 섹션 소제목 |
| `left_sections[].body` | O | string | 섹션 본문 (줄바꿈 허용) |
| `right_sections[]` | O | array | 우측 섹션 배열 |
| `right_sections[].title` | O | string | 섹션 소제목 |
| `right_sections[].body` | O | string | 섹션 본문 |
| `left_color_theme` | X | string | 좌측 테마 (기본: warm) |
| `right_color_theme` | X | string | 우측 테마 (기본: teal) |
### 3.3 동적 재구성 규칙 (★ 가장 수학적으로 복잡)
#### 그리드 계산
```
container_width에서 2열 분할:
col_width = (container_width - gap) / 2
gap = 0px (그라디언트가 맞닿음)
```
#### 섹션 높이 계산 (핵심)
```
header_bar_height = 48px (고정)
각 섹션의 높이:
section_height(s) =
title_height(s.title, title_font_size, col_width) +
body_height(s.body, body_font_size, col_width) +
section_padding
title_height = ceil(char_count / chars_per_line) * title_line_height
body_height = line_count * body_line_height
chars_per_line = floor(col_width / (font_size * 0.55)) // 한글 평균 0.55em
좌측 전체:
left_total = header_bar + sum(section_height for s in left_sections) + gaps
우측 전체:
right_total = header_bar + sum(section_height for s in right_sections) + gaps
content_height = max(left_total, right_total)
```
#### 오버플로 방지 — Fit 검증
```
if content_height > container_available_height:
전략 1: 폰트 축소
body_font_size -= 1px (최소 12px)
재계산
전략 2: 섹션 본문 줄 수 제한
max_body_lines = floor(
(available_per_section - title_height) / body_line_height
)
available_per_section = (container_height - header*2 - gaps) / max(N_left, N_right)
전략 3: Kei 에스컬레이션 (기존 파이프라인)
content 요약 요청
```
#### 색상 테마 매핑
```
warm (좌측 기본):
header_gradient: rgba(165,161,150,0.10) → rgba(57,50,30,1.00)
section_title_color: var(--color-warm-brown)
bg: rgba(255,255,255,0.30) → rgba(57,50,30,0.30)
teal (우측 기본):
header_gradient: rgba(41,107,85,0.10) → rgba(3,33,24,1.00)
section_title_color: var(--color-dark-teal)
bg: rgba(41,107,85,0.30) → rgba(255,255,255,0.30)
```
### 3.4 catalog.yaml schema
```yaml
- id: compare-detail-gradient
name: 그라디언트 상세 2열 비교
category: cards
template: blocks/cards/compare-detail-gradient.html
height_cost: xlarge
min_height_px: 300
relation_types: [comparison, contrast, process]
min_items: 2 # 좌/우 최소 1섹션씩
max_items: 10 # 좌+우 합계
visual: >
좌우 그라디언트 배경(워 브라운 vs 다크틸)으로 나뉜 2열 비교.
각 열 상단에 그라디언트 헤더 바 + 큰 제목(28px/900).
하단에 N개 섹션(소제목 22px/900 + 본문 16px/700) 반복.
좌측은 따뜻한 톤(과정/As-Is), 우측은 차가운 톤(결과/To-Be).
when: >
두 카테고리를 상세하게 비교할 때.
각 카테고리에 여러 하위 항목이 있을 때.
과정 vs 결과, As-Is vs To-Be, 문제 vs 해결 구조.
not_for: >
간단한 2항목 비교(본문 짧을 때) → compare-2col-badge.
3열 비교 → compare-3col-badge.
비교가 아닌 단독 리스트 → dark-bullet-list.
purpose_fit: [비교대조, 구조시각화, 근거사례]
zone: full-width-only
slots:
required: [left_header, right_header, left_sections[], right_sections[]]
optional: [left_color_theme, right_color_theme]
schema:
left_header:
max_lines: 1
font_size: 28
ref_chars:
body: 20
note: "28px black/900, 그라디언트 바 위"
right_header:
max_lines: 1
font_size: 28
ref_chars:
body: 20
note: "28px black/900, 그라디언트 바 위"
section_title:
max_lines: 2
font_size: 22
ref_chars:
body: 30
note: "22px/900, 색상 테마별 (브라운 or 틸)"
section_body:
max_lines: 4
font_size: 16
ref_chars:
body: 120
note: "16px/700, black"
padding_overhead_px: 48
padding_h_px: 0
```
---
## 서브 컴포넌트
### S1. 장식 이미지 (3D 화살표 등)
- 블록이 아닌 **콘텐츠 이미지**로 처리
- `cards[].icon` 또는 별도 `decoration_image` 슬롯으로 전달
- 블록은 `<img>` 태그로 렌더링, 크기는 CSS로 컨테이너에 맞춤
### S2. CTA 버튼
- 독립 블록이 아닌 **다른 블록 내 선택적 요소**
- `cta_text` 슬롯으로 전달 (없으면 미표시)
- CSS: 그라디언트 바 + 둥근 버튼 (r:7)
---
## 구현 우선순위
| 순서 | 블록 | 이유 |
|------|------|------|
| 1 (파일럿) | `compare-2col-badge` | 중간 복잡도, 기존 compare-2col-split과 비교 검증 가능 |
| 2 | `hero-icon-cards` | N개 카드 그리드 계산 필요, 파일럿 경험 활용 |
| 3 | `compare-detail-gradient` | 가장 복잡 (N개 섹션 × 2열, 높이 균형, 오버플로 방지) |