phase z catalog: Step 7-A (layouts) + 8-A (regions/display) 박힘
사용자 lock 2026-05-07 — catalog data 는 yaml/HTML 에서 사람이 보고 modify 가능 (= hardcoded dict 위배 제거). 추가: - templates/phase_z2/layouts/layouts.yaml — 8 preset (single / horizontal-2 / vertical-2 / top-1-bottom-2 / top-2-bottom-1 / left-1-right-2 / left-2-right-1 / grid-2x2). 기존 hardcoded LAYOUT_PRESETS dict (src/phase_z2_composition.py) → catalog 이전. backward compat (load_layout_presets() 가 같은 dict shape). 필드: zones / topology / positions / css_areas / css_cols / css_rows / render_ready / default_selection / candidate_when. (Step 7-A) - templates/phase_z2/layouts/layouts_preview.html — 8 preset 시각 검증. - templates/phase_z2/regions/region_layouts.yaml — Internal Region 6 entry (region-single / vertical-stack / horizontal-split / main-support / preview-details / grid-2x2). SPEC §2.5 의 sequential first-match decision tree. region-vertical-stack only default_fallback. (Step 8-A) - templates/phase_z2/regions/display_strategies.yaml — display 4 entry (inline_full / inline_preview_with_details / details_only / dropped). applies_to / forbidden_for / detail_trigger.placement: top-right. 사용자 절대 lock: text/table/image/details 절대 dropped X (forbidden_for). - templates/phase_z2/regions/regions_preview.html — 6 region + 4 display 카드 시각 검증 (axis 분리 lock — region structure ≠ display policy). axis 분리 lock (사용자 2026-05-07): - region (structure axis) ≠ display (policy axis) → 두 catalog 분리. - preserves_original 은 display_strategies 의 single source of truth. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
130
templates/phase_z2/layouts/layouts.yaml
Normal file
130
templates/phase_z2/layouts/layouts.yaml
Normal file
@@ -0,0 +1,130 @@
|
||||
# Phase Z 8-preset Layout Catalog
|
||||
#
|
||||
# User lock (2026-05-07) — Step 7-A:
|
||||
# Layout definitions migrated from hardcoded dict (src/phase_z2_composition.py
|
||||
# LAYOUT_PRESETS) to this catalog. Logic unchanged — backward compat
|
||||
# (load_layout_presets() returns same dict shape).
|
||||
#
|
||||
# Hierarchy:
|
||||
# slide_base (templates/phase_z2/slide_base.html)
|
||||
# -> layout (this catalog)
|
||||
# -> zone (positions)
|
||||
# -> frame family partial (templates/phase_z2/families/*.html)
|
||||
# -> slot payload
|
||||
#
|
||||
# Per-layout fields:
|
||||
# render_ready: bool
|
||||
# - true: layout has full grid definition + verified rendering path
|
||||
# - false: layout defined but render path incomplete (future-proof marker)
|
||||
# default_selection: bool
|
||||
# - true: select_layout_preset() picks this as default for matching unit_count
|
||||
# - false: defined alternative — not picked by current single-decision logic
|
||||
# (consumed by Step 7-B multiple-candidate generation, Step 9 fit eval)
|
||||
# candidate_when:
|
||||
# unit_count + optional signals (orientation / layout topology hint)
|
||||
# used by Step 7-B / Step 9 (currently inert — single-decision logic in
|
||||
# select_layout_preset() ignores this field).
|
||||
# unit_count = layout placement unit count (Step 4 output) =
|
||||
# raw section_count + promoted lead_orphans 등.
|
||||
|
||||
single:
|
||||
zones: 1
|
||||
topology: single
|
||||
positions: [primary]
|
||||
css_areas: '"primary"'
|
||||
css_cols: 1fr
|
||||
css_rows: 1fr
|
||||
render_ready: true
|
||||
default_selection: true
|
||||
candidate_when:
|
||||
unit_count: 1
|
||||
|
||||
horizontal-2:
|
||||
zones: 2
|
||||
topology: rows
|
||||
positions: [top, bottom]
|
||||
css_areas: '"top" "bottom"'
|
||||
css_cols: 1fr
|
||||
css_rows: 1fr 1fr
|
||||
render_ready: true
|
||||
default_selection: true
|
||||
candidate_when:
|
||||
unit_count: 2
|
||||
orientation: horizontal
|
||||
|
||||
vertical-2:
|
||||
zones: 2
|
||||
topology: cols
|
||||
positions: [left, right]
|
||||
css_areas: '"left right"'
|
||||
css_cols: 1fr 1fr
|
||||
css_rows: 1fr
|
||||
render_ready: true
|
||||
default_selection: false
|
||||
candidate_when:
|
||||
unit_count: 2
|
||||
orientation: vertical
|
||||
|
||||
top-1-bottom-2:
|
||||
zones: 3
|
||||
topology: T
|
||||
positions: [top, bottom-left, bottom-right]
|
||||
css_areas: '"top top" "bottom-left bottom-right"'
|
||||
css_cols: 1fr 1fr
|
||||
css_rows: 1fr 1fr
|
||||
render_ready: true
|
||||
default_selection: true
|
||||
candidate_when:
|
||||
unit_count: 3
|
||||
layout: T
|
||||
|
||||
top-2-bottom-1:
|
||||
zones: 3
|
||||
topology: inverted-T
|
||||
positions: [top-left, top-right, bottom]
|
||||
css_areas: '"top-left top-right" "bottom bottom"'
|
||||
css_cols: 1fr 1fr
|
||||
css_rows: 1fr 1fr
|
||||
render_ready: true
|
||||
default_selection: false
|
||||
candidate_when:
|
||||
unit_count: 3
|
||||
layout: inverted-T
|
||||
|
||||
left-1-right-2:
|
||||
zones: 3
|
||||
topology: side-T-left
|
||||
positions: [left, right-top, right-bottom]
|
||||
css_areas: '"left right-top" "left right-bottom"'
|
||||
css_cols: 1fr 1fr
|
||||
css_rows: 1fr 1fr
|
||||
render_ready: true
|
||||
default_selection: false
|
||||
candidate_when:
|
||||
unit_count: 3
|
||||
layout: side-T-left
|
||||
|
||||
left-2-right-1:
|
||||
zones: 3
|
||||
topology: side-T-right
|
||||
positions: [left-top, right, left-bottom]
|
||||
css_areas: '"left-top right" "left-bottom right"'
|
||||
css_cols: 1fr 1fr
|
||||
css_rows: 1fr 1fr
|
||||
render_ready: true
|
||||
default_selection: false
|
||||
candidate_when:
|
||||
unit_count: 3
|
||||
layout: side-T-right
|
||||
|
||||
grid-2x2:
|
||||
zones: 4
|
||||
topology: 2x2
|
||||
positions: [top-left, top-right, bottom-left, bottom-right]
|
||||
css_areas: '"top-left top-right" "bottom-left bottom-right"'
|
||||
css_cols: 1fr 1fr
|
||||
css_rows: 1fr 1fr
|
||||
render_ready: true
|
||||
default_selection: true
|
||||
candidate_when:
|
||||
unit_count: 4
|
||||
121
templates/phase_z2/layouts/layouts_preview.html
Normal file
121
templates/phase_z2/layouts/layouts_preview.html
Normal file
@@ -0,0 +1,121 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Phase Z 8-preset Layout Catalog Preview</title>
|
||||
<style>
|
||||
body { font-family: 'Pretendard', 'Noto Sans KR', sans-serif; padding: 24px; max-width: 1400px; margin: 0 auto; background: #f1f5f9; color: #1e293b; }
|
||||
h1 { border-bottom: 2px solid #333; padding-bottom: 8px; margin-top: 0; }
|
||||
.grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; margin-top: 24px; }
|
||||
.card { background: #fff; border: 1px solid #cbd5e1; border-radius: 8px; padding: 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); }
|
||||
.card h2 { margin-top: 0; font-size: 18px; display: flex; justify-content: space-between; align-items: center; }
|
||||
.badge { font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 999px; }
|
||||
.badge.default-selection { background: #dcfce7; color: #166534; }
|
||||
.badge.alternative { background: #e2e8f0; color: #475569; }
|
||||
.meta { font-size: 13px; color: #64748b; margin-bottom: 12px; }
|
||||
.meta code { background: #f1f5f9; padding: 1px 6px; border-radius: 3px; }
|
||||
.preview { width: 100%; aspect-ratio: 16/9; border: 1px solid #94a3b8; background: #fafafa; padding: 8px; box-sizing: border-box; }
|
||||
.zone { background: #dbeafe; border: 2px solid #3b82f6; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; color: #1e40af; padding: 4px; box-sizing: border-box; }
|
||||
.zone:nth-child(2) { background: #fef3c7; border-color: #f59e0b; color: #92400e; }
|
||||
.zone:nth-child(3) { background: #dcfce7; border-color: #16a34a; color: #166534; }
|
||||
.zone:nth-child(4) { background: #fce7f3; border-color: #db2777; color: #9f1239; }
|
||||
.when { margin-top: 12px; font-size: 13px; }
|
||||
.when strong { color: #475569; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Phase Z 8-preset Layout Catalog</h1>
|
||||
<p>source: <code>templates/phase_z2/layouts/layouts.yaml</code> / 사람이 8 layout 시각 검증용. <strong>default selection</strong> = 현재 select_layout_preset() 단일 결정 로직에서 자동 선택. <strong>alternative</strong> = render_ready 이지만 자동 선택 안 됨 (Step 7-B 후보 활성화 대상).</p>
|
||||
|
||||
<div class="grid">
|
||||
|
||||
<div class="card">
|
||||
<h2>single <span class="badge default-selection">default selection</span></h2>
|
||||
<div class="meta">zones: 1 / topology: single / positions: <code>[primary]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'primary'; grid-template-columns:1fr; grid-template-rows:1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:primary;">primary</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 1</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>horizontal-2 <span class="badge default-selection">default selection</span></h2>
|
||||
<div class="meta">zones: 2 / topology: rows / positions: <code>[top, bottom]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'top' 'bottom'; grid-template-columns:1fr; grid-template-rows:1fr 1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:top;">top</div>
|
||||
<div class="zone" style="grid-area:bottom;">bottom</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 2 / orientation = horizontal</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>vertical-2 <span class="badge alternative">alternative</span></h2>
|
||||
<div class="meta">zones: 2 / topology: cols / positions: <code>[left, right]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'left right'; grid-template-columns:1fr 1fr; grid-template-rows:1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:left;">left</div>
|
||||
<div class="zone" style="grid-area:right;">right</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 2 / orientation = vertical</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>top-1-bottom-2 <span class="badge default-selection">default selection</span></h2>
|
||||
<div class="meta">zones: 3 / topology: T / positions: <code>[top, bottom-left, bottom-right]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'top top' 'bottom-left bottom-right'; grid-template-columns:1fr 1fr; grid-template-rows:1fr 1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:top;">top</div>
|
||||
<div class="zone" style="grid-area:bottom-left;">bottom-left</div>
|
||||
<div class="zone" style="grid-area:bottom-right;">bottom-right</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 3 / layout = T</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>top-2-bottom-1 <span class="badge alternative">alternative</span></h2>
|
||||
<div class="meta">zones: 3 / topology: inverted-T / positions: <code>[top-left, top-right, bottom]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'top-left top-right' 'bottom bottom'; grid-template-columns:1fr 1fr; grid-template-rows:1fr 1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:top-left;">top-left</div>
|
||||
<div class="zone" style="grid-area:top-right;">top-right</div>
|
||||
<div class="zone" style="grid-area:bottom;">bottom</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 3 / layout = inverted-T</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>left-1-right-2 <span class="badge alternative">alternative</span></h2>
|
||||
<div class="meta">zones: 3 / topology: side-T-left / positions: <code>[left, right-top, right-bottom]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'left right-top' 'left right-bottom'; grid-template-columns:1fr 1fr; grid-template-rows:1fr 1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:left;">left</div>
|
||||
<div class="zone" style="grid-area:right-top;">right-top</div>
|
||||
<div class="zone" style="grid-area:right-bottom;">right-bottom</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 3 / layout = side-T-left</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>left-2-right-1 <span class="badge alternative">alternative</span></h2>
|
||||
<div class="meta">zones: 3 / topology: side-T-right / positions: <code>[left-top, right, left-bottom]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'left-top right' 'left-bottom right'; grid-template-columns:1fr 1fr; grid-template-rows:1fr 1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:left-top;">left-top</div>
|
||||
<div class="zone" style="grid-area:right;">right</div>
|
||||
<div class="zone" style="grid-area:left-bottom;">left-bottom</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 3 / layout = side-T-right</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>grid-2x2 <span class="badge default-selection">default selection</span></h2>
|
||||
<div class="meta">zones: 4 / topology: 2x2 / positions: <code>[top-left, top-right, bottom-left, bottom-right]</code></div>
|
||||
<div class="preview" style="display:grid; grid-template-areas:'top-left top-right' 'bottom-left bottom-right'; grid-template-columns:1fr 1fr; grid-template-rows:1fr 1fr; gap:8px;">
|
||||
<div class="zone" style="grid-area:top-left;">top-left</div>
|
||||
<div class="zone" style="grid-area:top-right;">top-right</div>
|
||||
<div class="zone" style="grid-area:bottom-left;">bottom-left</div>
|
||||
<div class="zone" style="grid-area:bottom-right;">bottom-right</div>
|
||||
</div>
|
||||
<div class="when"><strong>candidate_when:</strong> unit_count = 4</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user