feat(catalog): activate three_persona_benefits frame (IMP-04 #4 / 1 of 7)
Reason : V4 use_as_is=1 (frame_number=14, frame_id=1171281191).
Pattern : cards-3col-persona — 발주자/시공자/설계자 3 주체 각 benefit.
- Append `three_persona_benefits` contract to frame_contracts.yaml after
the existing F13/F29/F16 entries (Codex Catch 1/4: YAML order = trace
selection surface)
- Reuse existing builder primitives: items_with_role + quadrant_item
parser. No new entry in PAYLOAD_BUILDERS / ITEM_PARSERS.
Output dict shape: payload.personas = [{label, body, color_class}, ...]
- Add families/three_persona_benefits.html partial:
- Pure CSS (no Figma raster img tags) per memory rule
`feedback_blocks_must_be_css.md`
- PROMOTED colors per persona (#285b4a client / #445a2f constructor /
#743002 designer) from Figma TEXT layers
- NOT PROMOTED: col_bg_texture / overlay / 하단 사진 / 원형 뱃지 inner-outer
image — all replaced by CSS approximation (pill badge + colored
border + check-style text-line bullets)
- Token-fixed typography (zone-title / sub-title / caption / body)
- data-frame-id="1171281191" data-template-id attributes
- Add bundled smoke fixture for three_persona_benefits to
scripts/smoke_frame_render.py
- visual_hints.min_height_px = 280 (initial estimate between F13=230 and
F29=345 for 3-card text-heavy layout). Refine during batch full
pipeline if needed.
- accepted_content_types = [text_block] only (rich types not routed yet
per IMP-03 scope-lock).
Verification :
- isolated Jinja StrictUndefined smoke (scripts/smoke_frame_render.py
--self-check) : PASS=4/4 (existing 3 + new persona, 3889 chars)
- regression run on MDX 03 (env OFF + rich OFF) : PASS — MDX 03 V4
rank-1 still F13/F29 so the new entry does not affect existing flow
scope-lock 15 conditions all honored (no V4 / mapper / Phase R' / Step
6+ changes; per-frame 6-step gate complete; YAML order preserved).
Refs Gitea #4 (IMP-04 A-2 Catalog 확장)
This commit is contained in:
@@ -136,10 +136,47 @@ _MOCK_QUADRANT = {
|
||||
"quadrant_4_body": [{"text": "가이드 부재", "indent": 0}],
|
||||
}
|
||||
|
||||
# IMP-04 frame 1 — three_persona_benefits (frame 14, frame_id=1171281191).
|
||||
# Builder = items_with_role + quadrant_item parser → persona dict = {label, body, color_class}.
|
||||
_MOCK_THREE_PERSONA_BENEFITS = {
|
||||
"title": "주체별 기대효과",
|
||||
"personas": [
|
||||
{
|
||||
"label": "발주자",
|
||||
"color_class": "client",
|
||||
"body": [
|
||||
{"text": "민원, 재 작업 등의 예방 및 최소화", "indent": 0},
|
||||
{"text": "직관화로 품질 향상 및 안정성 제고", "indent": 0},
|
||||
{"text": "수행공정의 쉬운이해로 관리 편의성 증진", "indent": 0},
|
||||
{"text": "실무자와 발주자간의 소통 오류 최소화", "indent": 0},
|
||||
],
|
||||
},
|
||||
{
|
||||
"label": "시공자",
|
||||
"color_class": "constructor",
|
||||
"body": [
|
||||
{"text": "시공 오류예방 및 공사 Risk 최소화", "indent": 0},
|
||||
{"text": "시각화로 안전성 제고 및 품질 향상", "indent": 0},
|
||||
{"text": "건설 관계자들 간의 의사소통 강화", "indent": 0},
|
||||
],
|
||||
},
|
||||
{
|
||||
"label": "설계자",
|
||||
"color_class": "designer",
|
||||
"body": [
|
||||
{"text": "직관적 시각화로 원활한 소통", "indent": 0},
|
||||
{"text": "3D 모델 활용으로 오류 최소화", "indent": 0},
|
||||
{"text": "발주자와의 상호 신뢰 증진", "indent": 0},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
SELF_CHECK_FIXTURES: dict[str, dict] = {
|
||||
"three_parallel_requirements": _MOCK_THREE_PARALLEL,
|
||||
"process_product_two_way": _MOCK_PROCESS_PRODUCT,
|
||||
"bim_issues_quadrant_four": _MOCK_QUADRANT,
|
||||
"three_persona_benefits": _MOCK_THREE_PERSONA_BENEFITS,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -179,3 +179,66 @@ bim_issues_quadrant_four:
|
||||
empty_body: []
|
||||
# implicit slot_order = [quadrant_1=TL, quadrant_2=TR, quadrant_3=BL, quadrant_4=BR]
|
||||
# 위치(TL/TR/BL/BR) 매핑은 partial template (families/bim_issues_quadrant_four.html) 결정.
|
||||
|
||||
|
||||
# ─── IMP-04 catalog 확장 (Gitea #4 scope-lock 7 frame) ───
|
||||
# 본 entry 들은 기존 3 entry (F13/F29/F16) *뒤에* append — YAML order 가
|
||||
# `list(load_frame_contracts().values())` 의 B4 trace 선택 순서 surface.
|
||||
# Reason 명시 (Codex Catch 5) : 각 frame 의 V4 use_as_is/light_edit 신호.
|
||||
|
||||
three_persona_benefits:
|
||||
# Reason : V4 use_as_is=1 (frame_number=14, frame_id=1171281191).
|
||||
# Pattern : cards-3col-persona (발주자/시공자/설계자 3 주체 각 benefit).
|
||||
template_id: three_persona_benefits
|
||||
frame_id: 1171281191
|
||||
family: cards
|
||||
|
||||
source_shape: top_bullets
|
||||
cardinality:
|
||||
strict: 3 # 3 persona = strict.
|
||||
overflow_policy: abort_or_review
|
||||
|
||||
# 순서 기반 color theme (Figma 원본 색).
|
||||
# client = 발주자 (#285b4a 그린 계열), constructor = 시공자 (#445a2f 올리브),
|
||||
# designer = 설계자 (#743002 적갈) — partial 의 .f14b__col--{role} 매핑.
|
||||
role_order:
|
||||
- client
|
||||
- constructor
|
||||
- designer
|
||||
|
||||
# min_height_px : initial estimate (3-card 텍스트 밀도 기준, F13=230 vs F29=345 사이).
|
||||
# smoke 통과 후 batch full-pipeline render 시 실측 갱신.
|
||||
visual_hints:
|
||||
min_height_px: 280
|
||||
|
||||
accepted_content_types:
|
||||
- text_block
|
||||
|
||||
# Frame Slot 선언 (SPEC v1 §3 layer B). 3 persona = 3 sub-zone.
|
||||
sub_zones:
|
||||
- id: persona_1
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f14b__cols > .f14b__col:nth-child(1)"
|
||||
- id: persona_2
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f14b__cols > .f14b__col:nth-child(2)"
|
||||
- id: persona_3
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
partial_target_path: ".f14b__cols > .f14b__col:nth-child(3)"
|
||||
|
||||
payload:
|
||||
title:
|
||||
source: section.title
|
||||
# builder 재사용 — F13 의 `items_with_role` + F16 의 `quadrant_item` parser.
|
||||
# quadrant_item = {label, body:[{text,indent}]} → persona card body 정합.
|
||||
builder: items_with_role
|
||||
builder_options:
|
||||
item_parser: quadrant_item # ITEM_PARSERS entry (F16 재사용)
|
||||
array_root: personas # payload.personas = list of items
|
||||
role_field: color_class # role_order[i] → item.color_class
|
||||
|
||||
123
templates/phase_z2/families/three_persona_benefits.html
Normal file
123
templates/phase_z2/families/three_persona_benefits.html
Normal file
@@ -0,0 +1,123 @@
|
||||
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
|
||||
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
|
||||
{#
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Visual Provenance — figma_to_html_agent/blocks/1171281191/ (frame 14)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Frame 14 = "주체별 기대효과" (cards-3col-persona, 2601×1927 px, scale 0.49213).
|
||||
Figma 원본 = 3 컬럼 카드, 각 카드 = 배경 텍스처 + 컬러 오버레이 + 원형 뱃지
|
||||
(persona 이름 + "목표") + 7 bullets + 하단 사진. token-fixed Phase Z partial.
|
||||
|
||||
PROMOTED (Figma 색 → CSS gradient / accent 보존) :
|
||||
- 발주자 accent : Figma TEXT #285b4a (dark green)
|
||||
- 시공자 accent : Figma TEXT #445a2f (olive)
|
||||
- 설계자 accent : Figma TEXT #743002 (red-brown)
|
||||
- title gradient : Figma #000 → #883700 (frame 13 과 동일 family 의 zone title)
|
||||
- card 외곽 border : 2px solid (frame 13 의 pillar bar 룰 따라)
|
||||
|
||||
NOT PROMOTED (Figma 데코지만 MDX 에 없으므로 주입 X — memory rule
|
||||
`feedback_blocks_must_be_css.md` : Figma SVG/PNG image slot 금지) :
|
||||
- col_bg_texture / overlay / 하단 사진 등 image asset
|
||||
- 원형 뱃지 inner/outer image — CSS round shape 으로 대체
|
||||
|
||||
ADAPTED :
|
||||
- Figma 65/50/40px → token-fixed (zone-title 13 / sub-title 12 / body 11)
|
||||
- badge 원형 → CSS circle (radial-gradient 의 accent border)
|
||||
- bullet check icon image → ::before 의 unicode check (∙ → ✓ approximate)
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
slots : title, personas[].{label, body, color_class}
|
||||
- color_class ∈ {client, constructor, designer} (role_order 따라)
|
||||
- body = list[{text:str, indent:int}] (parse_quadrant_item 출력)
|
||||
#}
|
||||
|
||||
<style>
|
||||
.f14b {
|
||||
width: 100%; height: 100%;
|
||||
display: flex; flex-direction: column;
|
||||
gap: 6px;
|
||||
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
|
||||
word-break: keep-all;
|
||||
}
|
||||
.f14b__title {
|
||||
font-size: var(--font-zone-title);
|
||||
font-weight: 700;
|
||||
line-height: var(--lh-zone-title);
|
||||
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
|
||||
-webkit-background-clip: text; background-clip: text;
|
||||
color: transparent;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.f14b__cols {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 10px;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
}
|
||||
.f14b__col {
|
||||
display: flex; flex-direction: column;
|
||||
border: 2px solid #000;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
background: #fff;
|
||||
}
|
||||
.f14b__col--client { border-color: #285b4a; } /* PROMOTED */
|
||||
.f14b__col--constructor { border-color: #445a2f; } /* PROMOTED */
|
||||
.f14b__col--designer { border-color: #743002; } /* PROMOTED */
|
||||
|
||||
/* badge — persona 라벨 + "목표" sub. Figma 원형 뱃지를 CSS pill 로 대체. */
|
||||
.f14b__badge {
|
||||
display: flex; align-items: baseline; justify-content: center;
|
||||
gap: 6px;
|
||||
padding: 6px 8px 4px;
|
||||
border-bottom: 2px solid currentColor;
|
||||
color: inherit;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.f14b__badge-name {
|
||||
font-size: var(--font-sub-title);
|
||||
font-weight: 700;
|
||||
line-height: var(--lh-sub-title);
|
||||
}
|
||||
.f14b__badge-suffix {
|
||||
font-size: var(--font-caption);
|
||||
font-weight: 500;
|
||||
opacity: 0.75;
|
||||
}
|
||||
.f14b__col--client .f14b__badge { color: #285b4a; }
|
||||
.f14b__col--constructor .f14b__badge { color: #445a2f; }
|
||||
.f14b__col--designer .f14b__badge { color: #743002; }
|
||||
|
||||
/* body — check-style bullet list. Figma image bullet → ::before unicode. */
|
||||
.f14b__body {
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
padding: 8px 10px;
|
||||
color: #1a1a1a;
|
||||
min-height: 0;
|
||||
}
|
||||
.f14b__body .text-line { color: inherit; }
|
||||
|
||||
/* Persona badge suffix label = static "목표" (Figma source) — slot 미사용,
|
||||
partial 안에서 직접 노출. content_object 와 무관한 frame 시각 언어. */
|
||||
</style>
|
||||
|
||||
<div class="f14b" data-frame-id="1171281191" data-template-id="three_persona_benefits">
|
||||
<div class="f14b__title">{{ slot_payload.title }}</div>
|
||||
<div class="f14b__cols">
|
||||
{% for persona in slot_payload.personas %}
|
||||
<div class="f14b__col f14b__col--{{ persona.color_class }}">
|
||||
<div class="f14b__badge">
|
||||
<span class="f14b__badge-name">{{ persona.label | safe }}</span>
|
||||
<span class="f14b__badge-suffix">목표</span>
|
||||
</div>
|
||||
<div class="f14b__body">
|
||||
{% if persona.body %}
|
||||
{% for line in persona.body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user