Vendor templates and prefer local template assets
This commit is contained in:
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 162 KiB After Width: | Height: | Size: 154 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 162 KiB After Width: | Height: | Size: 154 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -10,26 +10,26 @@
|
||||
"body": {
|
||||
"block_count": 0,
|
||||
"blocks": [],
|
||||
"clientHeight": 474,
|
||||
"excess_px": 0,
|
||||
"overflowed": false,
|
||||
"scrollHeight": 474
|
||||
"clientHeight": 483,
|
||||
"excess_px": 78,
|
||||
"overflowed": true,
|
||||
"scrollHeight": 561
|
||||
},
|
||||
"footer": {
|
||||
"block_count": 0,
|
||||
"blocks": [],
|
||||
"clientHeight": 56,
|
||||
"clientHeight": 52,
|
||||
"excess_px": 0,
|
||||
"overflowed": false,
|
||||
"scrollHeight": 56
|
||||
"scrollHeight": 52
|
||||
},
|
||||
"sidebar": {
|
||||
"block_count": 0,
|
||||
"blocks": [],
|
||||
"clientHeight": 474,
|
||||
"clientHeight": 483,
|
||||
"excess_px": 0,
|
||||
"overflowed": false,
|
||||
"scrollHeight": 474
|
||||
"scrollHeight": 483
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"body_bg": {
|
||||
"passed": true,
|
||||
"score": 1.0,
|
||||
"score": 0.9666666666666667,
|
||||
"errors": []
|
||||
},
|
||||
"body_core": {
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
22
docs/run-001/05-execution/steps/stage_0.html
Normal file
22
docs/run-001/05-execution/steps/stage_0.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html><html><head><meta charset="UTF-8">
|
||||
<style>*{margin:0;padding:0;box-sizing:border-box;}body{background:#e5e5e5;padding:10px;font-family:sans-serif;word-break:keep-all;}</style>
|
||||
</head><body>
|
||||
<div style="font-size:16px;font-weight:bold;margin-bottom:8px;">Stage 0: MDX 정규화</div>
|
||||
<div style="font-size:12px;color:#555;margin-bottom:12px;">제목: <b>건설산업 DX의 올바른 이해</b> | 섹션: 3개 | 팝업: 2개 | 이미지: 1개 | 테이블: 0개</div>
|
||||
<div style="font-size:13px;font-weight:700;margin-bottom:4px;">섹션</div>
|
||||
<table style="border-collapse:collapse;font-size:12px;width:100%;max-width:900px;margin-bottom:16px;">
|
||||
<tr style="background:#1e293b;color:white;"><th style="padding:8px;">#</th><th style="padding:8px;">heading</th><th style="padding:8px;">content (미리보기)</th></tr><tr style="background:#f8fafc;"><td style="padding:6px 8px;">1</td><td style="padding:6px 8px;font-weight:700;"></td><td style="padding:6px 8px;font-size:11px;">건설산업의 디지털 전환 논의에서 DX(Digital Transformation)와 BIM(Building Information Modeling)이 개념적으로 명확히 정립되지 않은채 혼용되어 사용되고 있음
|
||||
이로인해 B...</td></tr>
|
||||
<tr style="background:#fff;"><td style="padding:6px 8px;">2</td><td style="padding:6px 8px;font-weight:700;"></td><td style="padding:6px 8px;font-size:11px;">**건설산업**
|
||||
다양한 시설물을 각 산업마다의 광범위한 기술을 통합 및 융합하여 만들어내는 종합산업
|
||||
목적 시설물의 품질 욕구를 충족시키면서 최단기간내에 최소 비용으로 편리하고 안전하며 우수한 성능의 시설물 완성을 목...</td></tr>
|
||||
<tr style="background:#f8fafc;"><td style="padding:6px 8px;">3</td><td style="padding:6px 8px;font-weight:700;"></td><td style="padding:6px 8px;font-size:11px;">DX는 BIM과 같은 디지털기술을 기반으로 산업 전반의 프로세스를 혁신하는 상위개념
|
||||
건설산업의 DX는 GIS(공간정보), BIM, 디지털 트윈(가상환경)의 기술융합을 통해서만 실현 또는 구현 가능
|
||||
GIS의 역할 : ...</td></tr>
|
||||
</table>
|
||||
<div style="font-size:13px;font-weight:700;margin-bottom:4px;">팝업</div>
|
||||
<table style="border-collapse:collapse;font-size:12px;width:100%;max-width:600px;">
|
||||
<tr style="background:#1e293b;color:white;"><th style="padding:8px;">title</th><th style="padding:8px;">분량</th></tr><tr><td style="padding:6px 8px;font-weight:700;">혼용 대표 사례</td><td style="padding:6px 8px;font-size:11px;">340자</td></tr>
|
||||
<tr><td style="padding:6px 8px;font-weight:700;">DX와 BIM의 구분</td><td style="padding:6px 8px;font-size:11px;">1135자</td></tr>
|
||||
</table>
|
||||
</body></html>
|
||||
16
docs/run-001/05-execution/steps/stage_1_5a.html
Normal file
16
docs/run-001/05-execution/steps/stage_1_5a.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html><html><head><meta charset="UTF-8">
|
||||
<style>
|
||||
*{margin:0;padding:0;box-sizing:border-box;}
|
||||
body{background:#e5e5e5;padding:10px;font-family:'Pretendard Variable','Noto Sans KR',sans-serif;word-break:keep-all;}
|
||||
.bl{display:flex;gap:0;margin-bottom:2px;}.bl-m{flex-shrink:0;width:1em;}.bl-t{flex:1;}
|
||||
</style></head><body>
|
||||
<div style="font-size:16px;font-weight:bold;margin-bottom:4px;">Step 1: 빈 컨테이너 (Stage 1.5a)</div>
|
||||
<div style="font-size:11px;color:#666;margin-bottom:8px;">비율 64:36</div>
|
||||
<div style="width:1280px;height:720px;background:white;position:relative;border:1px solid #ccc;">
|
||||
<div style="position:absolute;left:40px;top:40px;width:1200px;height:66px;background:#f8fafc;border-bottom:3px solid #2563eb;display:flex;align-items:center;padding:0 20px;font-size:22px;font-weight:900;color:#1e293b;">건설산업 DX의 올바른 이해</div>
|
||||
<div style="position:absolute;left:40px;top:126px;width:768px;height:143px;border:2px solid #dc2626;border-radius:6px;background:#dc262608;overflow:hidden;"><div style="text-align:center;margin-top:56px;"><b style="color:#dc2626;font-size:13px;">배경</b><br><span style="color:#888;font-size:10px;">768x143px / font:12.0px</span></div></div>
|
||||
<div style="position:absolute;left:40px;top:277px;width:768px;height:326px;border:2px solid #2563eb;border-radius:6px;background:#2563eb08;overflow:hidden;"><div style="text-align:center;margin-top:148px;"><b style="color:#2563eb;font-size:13px;">본심</b><br><span style="color:#888;font-size:10px;">768x326px / font:12.0px</span></div></div>
|
||||
<div style="position:absolute;left:828px;top:126px;width:412px;height:490px;border:2px solid #16a34a;border-radius:6px;background:#16a34a08;overflow:hidden;"><div style="text-align:center;margin-top:230px;"><b style="color:#16a34a;font-size:13px;">첨부</b><br><span style="color:#888;font-size:10px;">412x490px / font:11.0px</span></div></div>
|
||||
<div style="position:absolute;left:40px;top:636px;width:1200px;height:60px;border:2px solid #7c3aed;border-radius:6px;background:#7c3aed08;overflow:hidden;"><div style="text-align:center;margin-top:15px;"><b style="color:#7c3aed;font-size:13px;">결론</b><br><span style="color:#888;font-size:10px;">1200x60px / font:14.0px</span></div></div>
|
||||
|
||||
</div></body></html>
|
||||
16
docs/run-001/05-execution/steps/stage_1_5a_content.html
Normal file
16
docs/run-001/05-execution/steps/stage_1_5a_content.html
Normal file
File diff suppressed because one or more lines are too long
16
docs/run-001/05-execution/steps/stage_1_5b.html
Normal file
16
docs/run-001/05-execution/steps/stage_1_5b.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html><html><head><meta charset="UTF-8">
|
||||
<style>
|
||||
*{margin:0;padding:0;box-sizing:border-box;}
|
||||
body{background:#e5e5e5;padding:10px;font-family:'Pretendard Variable','Noto Sans KR',sans-serif;word-break:keep-all;}
|
||||
.bl{display:flex;gap:0;margin-bottom:2px;}.bl-m{flex-shrink:0;width:1em;}.bl-t{flex:1;}
|
||||
</style></head><body>
|
||||
<div style="font-size:16px;font-weight:bold;margin-bottom:4px;">Stage 1.5b: 디자인 예산</div>
|
||||
<div style="font-size:11px;color:#666;margin-bottom:8px;">영역별 available_height/width + fits 여부</div>
|
||||
<div style="width:1280px;height:720px;background:white;position:relative;border:1px solid #ccc;">
|
||||
<div style="position:absolute;left:40px;top:40px;width:1200px;height:66px;background:#f8fafc;border-bottom:3px solid #2563eb;display:flex;align-items:center;padding:0 20px;font-size:22px;font-weight:900;color:#1e293b;">건설산업 DX의 올바른 이해</div>
|
||||
<div style="position:absolute;left:40px;top:126px;width:768px;height:143px;border:2px solid #dc2626;border-radius:6px;background:#dc262608;overflow:hidden;"><div style="padding:6px 10px;"><div style="font-size:10px;color:#dc2626;font-weight:700;">✅ 배경 (768×143px)</div><div style="font-size:10px;color:#555;">available: 5×740px</div><div style="font-size:10px;color:#555;">fits: True</div></div></div>
|
||||
<div style="position:absolute;left:40px;top:277px;width:768px;height:326px;border:2px solid #2563eb;border-radius:6px;background:#2563eb08;overflow:hidden;"><div style="padding:6px 10px;"><div style="font-size:10px;color:#2563eb;font-weight:700;">✅ 본심 (768×326px)</div><div style="font-size:10px;color:#555;">available: 220×740px</div><div style="font-size:10px;color:#555;">fits: True</div></div></div>
|
||||
<div style="position:absolute;left:828px;top:126px;width:412px;height:490px;border:2px solid #16a34a;border-radius:6px;background:#16a34a08;overflow:hidden;"><div style="padding:6px 10px;"><div style="font-size:10px;color:#16a34a;font-weight:700;">✅ 첨부 (412×490px)</div><div style="font-size:10px;color:#555;">available: 372×380px</div><div style="font-size:10px;color:#555;">fits: True</div></div></div>
|
||||
<div style="position:absolute;left:40px;top:636px;width:1200px;height:60px;border:2px solid #7c3aed;border-radius:6px;background:#7c3aed08;overflow:hidden;"><div style="padding:6px 10px;"><div style="font-size:10px;color:#7c3aed;font-weight:700;">⚠️ 결론 (1200×60px)</div><div style="font-size:10px;color:#555;">available: 0×1160px</div><div style="font-size:10px;color:#555;">fits: False</div></div></div>
|
||||
|
||||
</div></body></html>
|
||||
16
docs/run-001/05-execution/steps/stage_1_7.html
Normal file
16
docs/run-001/05-execution/steps/stage_1_7.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html><html><head><meta charset="UTF-8">
|
||||
<style>
|
||||
*{margin:0;padding:0;box-sizing:border-box;}
|
||||
body{background:#e5e5e5;padding:10px;font-family:'Pretendard Variable','Noto Sans KR',sans-serif;word-break:keep-all;}
|
||||
.bl{display:flex;gap:0;margin-bottom:2px;}.bl-m{flex-shrink:0;width:1em;}.bl-t{flex:1;}
|
||||
</style></head><body>
|
||||
<div style="font-size:16px;font-weight:bold;margin-bottom:4px;">Step 2: 블록 선택 (Stage 1.7)</div>
|
||||
<div style="font-size:11px;color:#666;margin-bottom:8px;">layer 기반 주종 판단. 컨테이너 위에 블록 표시.</div>
|
||||
<div style="width:1280px;height:720px;background:white;position:relative;border:1px solid #ccc;">
|
||||
<div style="position:absolute;left:40px;top:40px;width:1200px;height:66px;background:#f8fafc;border-bottom:3px solid #2563eb;display:flex;align-items:center;padding:0 20px;font-size:22px;font-weight:900;color:#1e293b;">건설산업 DX의 올바른 이해</div>
|
||||
<div style="position:absolute;left:40px;top:126px;width:768px;height:143px;border:2px solid #dc2626;border-radius:6px;background:#dc262608;overflow:hidden;"><div style="padding:6px 10px;"><div style="font-size:10px;color:#dc2626;font-weight:700;margin-bottom:4px;">배경 (768x143px)</div><div style="font-size:11px;margin-bottom:2px;"><b>quote-big-mark</b> (default) <span style="color:#888;font-size:9px;">default</span></div></div></div>
|
||||
<div style="position:absolute;left:40px;top:277px;width:768px;height:326px;border:2px solid #2563eb;border-radius:6px;background:#2563eb08;overflow:hidden;"><div style="padding:6px 10px;"><div style="font-size:10px;color:#2563eb;font-weight:700;margin-bottom:4px;">본심 (768x326px)</div><div style="font-size:11px;margin-bottom:2px;"><b>card-dark-overlay</b> (default) <span style="color:#888;font-size:9px;">default</span></div><div style="font-size:11px;margin-bottom:2px;"><b>circle-gradient</b> (default) <span style="color:#888;font-size:9px;">default</span></div></div></div>
|
||||
<div style="position:absolute;left:828px;top:126px;width:412px;height:490px;border:2px solid #16a34a;border-radius:6px;background:#16a34a08;overflow:hidden;"><div style="padding:6px 10px;"><div style="font-size:10px;color:#16a34a;font-weight:700;margin-bottom:4px;">첨부 (412x490px)</div><div style="font-size:11px;margin-bottom:2px;"><b>card-image-3col</b> (default) <span style="color:#888;font-size:9px;">default</span></div></div></div>
|
||||
<div style="position:absolute;left:40px;top:636px;width:1200px;height:60px;border:2px solid #7c3aed;border-radius:6px;background:#7c3aed08;overflow:hidden;"><div style="padding:6px 10px;"><div style="font-size:10px;color:#7c3aed;font-weight:700;margin-bottom:4px;">결론 (1200x60px)</div><div style="font-size:11px;margin-bottom:2px;"><b>banner-gradient</b> (default) <span style="color:#888;font-size:9px;">default</span></div></div></div>
|
||||
|
||||
</div></body></html>
|
||||
15
docs/run-001/05-execution/steps/stage_1a.html
Normal file
15
docs/run-001/05-execution/steps/stage_1a.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html><html><head><meta charset="UTF-8">
|
||||
<style>*{margin:0;padding:0;box-sizing:border-box;}body{background:#e5e5e5;padding:10px;font-family:sans-serif;word-break:keep-all;}</style>
|
||||
</head><body>
|
||||
<div style="font-size:16px;font-weight:bold;margin-bottom:8px;">Stage 1A/1B: Kei 꼭지 + 영역 배정</div>
|
||||
<table style="border-collapse:collapse;font-size:12px;width:100%;max-width:900px;">
|
||||
<tr style="background:#1e293b;color:white;"><th style="padding:8px;">ID</th><th style="padding:8px;">제목</th>
|
||||
<th style="padding:8px;">purpose</th><th style="padding:8px;">layer</th><th style="padding:8px;">relation_type</th>
|
||||
<th style="padding:8px;">영역</th></tr><tr style="background:#fff;"><td style="padding:6px 8px;text-align:center;">1</td><td style="padding:6px 8px;font-weight:700;">용어의 혼용</td><td style="padding:6px 8px;">문제제기</td><td style="padding:6px 8px;">intro</td><td style="padding:6px 8px;"></td><td style="padding:6px 8px;color:#dc2626;font-weight:700;">배경</td></tr>
|
||||
<tr style="background:#f8fafc;"><td style="padding:6px 8px;text-align:center;">2</td><td style="padding:6px 8px;font-weight:700;">용어 정의</td><td style="padding:6px 8px;">정의정립</td><td style="padding:6px 8px;">core</td><td style="padding:6px 8px;"></td><td style="padding:6px 8px;color:#2563eb;font-weight:700;">본심</td></tr>
|
||||
<tr style="background:#fff;"><td style="padding:6px 8px;text-align:center;">3</td><td style="padding:6px 8px;font-weight:700;">용어간 상호관계</td><td style="padding:6px 8px;">관계설명</td><td style="padding:6px 8px;">core</td><td style="padding:6px 8px;"></td><td style="padding:6px 8px;color:#2563eb;font-weight:700;">본심</td></tr>
|
||||
<tr style="background:#f8fafc;"><td style="padding:6px 8px;text-align:center;">4</td><td style="padding:6px 8px;font-weight:700;">혼용 대표 사례</td><td style="padding:6px 8px;">근거사례</td><td style="padding:6px 8px;">supporting</td><td style="padding:6px 8px;"></td><td style="padding:6px 8px;color:#dc2626;font-weight:700;">배경</td></tr>
|
||||
<tr style="background:#fff;"><td style="padding:6px 8px;text-align:center;">5</td><td style="padding:6px 8px;font-weight:700;">DX와 BIM의 구분</td><td style="padding:6px 8px;">비교근거</td><td style="padding:6px 8px;">supporting</td><td style="padding:6px 8px;"></td><td style="padding:6px 8px;color:#16a34a;font-weight:700;">첨부</td></tr>
|
||||
<tr style="background:#f8fafc;"><td style="padding:6px 8px;text-align:center;">6</td><td style="padding:6px 8px;font-weight:700;">핵심 요약</td><td style="padding:6px 8px;">결론강조</td><td style="padding:6px 8px;">conclusion</td><td style="padding:6px 8px;"></td><td style="padding:6px 8px;color:#7c3aed;font-weight:700;">결론</td></tr>
|
||||
</table>
|
||||
<div style="margin-top:12px;font-size:12px;color:#555;"><b>페이지 구조:</b><br>배경: topic_ids=[1, 4], weight=0.22<br>본심: topic_ids=[2, 3], weight=0.5<br>첨부: topic_ids=[5], weight=0.18<br>결론: topic_ids=[6], weight=0.1</div></body></html>
|
||||
15
docs/run-001/05-execution/steps/stage_1b.html
Normal file
15
docs/run-001/05-execution/steps/stage_1b.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html><html><head><meta charset="UTF-8">
|
||||
<style>*{margin:0;padding:0;box-sizing:border-box;}body{background:#e5e5e5;padding:10px;font-family:sans-serif;word-break:keep-all;}</style>
|
||||
</head><body>
|
||||
<div style="font-size:16px;font-weight:bold;margin-bottom:8px;">Stage 1B: 컨셉 구체화</div>
|
||||
<div style="font-size:11px;color:#666;margin-bottom:8px;">Stage 1A의 꼭지에 source_data(원본 텍스트)와 summary가 추가됨</div>
|
||||
<table style="border-collapse:collapse;font-size:12px;width:100%;">
|
||||
<tr style="background:#1e293b;color:white;"><th style="padding:8px;">ID</th><th style="padding:8px;">제목</th>
|
||||
<th style="padding:8px;">영역</th><th style="padding:8px;">layer</th>
|
||||
<th style="padding:8px;">source_data (미리보기)</th><th style="padding:8px;">summary</th></tr><tr style="background:#fff;"><td style="padding:6px 8px;text-align:center;">1</td><td style="padding:6px 8px;font-weight:700;">용어의 혼용</td><td style="padding:6px 8px;color:#dc2626;">배경</td><td style="padding:6px 8px;">intro</td><td style="padding:6px 8px;font-size:10px;">**용어의 혼용** 건설산업의 디지털 전환 논의에서 DX(Digital Transformation)와 BIM(Building Information Modeling)이 개념적으로 명확히 정립되지 않은채 혼용되어 사용되고 있음 이로인해 BIM기술의 도입을 DX의 완성으로 ...</td><td style="padding:6px 8px;font-size:10px;color:#555;">**용어의 혼용** 건설산업의 디지털 전환 논의에서 DX(Digital Transformation)와 BIM(Building Information Modeling)이 개념적으로 명</td></tr>
|
||||
<tr style="background:#f8fafc;"><td style="padding:6px 8px;text-align:center;">2</td><td style="padding:6px 8px;font-weight:700;">용어 정의</td><td style="padding:6px 8px;color:#2563eb;">본심</td><td style="padding:6px 8px;">core</td><td style="padding:6px 8px;font-size:10px;">* **건설산업** * 다양한 시설물을 각 산업마다의 광범위한 기술을 통합 및 융합하여 만들어내는 종합산업 * 목적 시설물의 품질 욕구를 충족시키면서 최단기간내에 최소 비용으로 편리하고 안전하며 우수한 성능의 시설물 완성을 목표로 함 * **BIM(Building In...</td><td style="padding:6px 8px;font-size:10px;color:#555;">* **건설산업** * 다양한 시설물을 각 산업마다의 광범위한 기술을 통합 및 융합하여 만들어내는 종합산업 * 목적 시설물의 품질 욕구를 충족시키면서 최단기간내에 최소 비용으로 편</td></tr>
|
||||
<tr style="background:#fff;"><td style="padding:6px 8px;text-align:center;">3</td><td style="padding:6px 8px;font-weight:700;">용어간 상호관계</td><td style="padding:6px 8px;color:#2563eb;">본심</td><td style="padding:6px 8px;">core</td><td style="padding:6px 8px;font-size:10px;">* DX는 BIM과 같은 디지털기술을 기반으로 산업 전반의 프로세스를 혁신하는 상위개념 * 건설산업의 DX는 GIS(공간정보), BIM, 디지털 트윈(가상환경)의 기술융합을 통해서만 실현 또는 구현 가능 * GIS의 역할 : 지리적 데이터를 공간 분석하여 시각적으로 표...</td><td style="padding:6px 8px;font-size:10px;color:#555;">* DX는 BIM과 같은 디지털기술을 기반으로 산업 전반의 프로세스를 혁신하는 상위개념 * 건설산업의 DX는 GIS(공간정보), BIM, 디지털 트윈(가상환경)의 기술융합을 통해서</td></tr>
|
||||
<tr style="background:#f8fafc;"><td style="padding:6px 8px;text-align:center;">4</td><td style="padding:6px 8px;font-weight:700;">혼용 대표 사례</td><td style="padding:6px 8px;color:#dc2626;">배경</td><td style="padding:6px 8px;">supporting</td><td style="padding:6px 8px;font-size:10px;">**[스마트 건설 활성화 방안(2022.07)]** 추진과제 : 건설산업 디지털화 실행과제 : BIM 전면 도입, BIM 전문인력 양성 **[제7차 건설기술진흥 기본계획(2023.12)]** 추진방향 : 디지털 전환을 통한 스마트 건설 확산 추진과제 : BIM 도입으로...</td><td style="padding:6px 8px;font-size:10px;color:#555;">**[스마트 건설 활성화 방안(2022.07)]** 추진과제 : 건설산업 디지털화 실행과제 : BIM 전면 도입, BIM 전문인력 양성 **[제7차 건설기술진흥 기본계획(2023.</td></tr>
|
||||
<tr style="background:#fff;"><td style="padding:6px 8px;text-align:center;">5</td><td style="padding:6px 8px;font-weight:700;">DX와 BIM의 구분</td><td style="padding:6px 8px;color:#16a34a;">첨부</td><td style="padding:6px 8px;">supporting</td><td style="padding:6px 8px;font-size:10px;">| DX | 구분 | BIM | | :--- | :---: | ---: | | **BIM << DX** (Engineering + Management 통합) | **범위** | **Only 3D** (형상 구현 중심) | | **제작 및 운영**(상용 + 전용 40~8...</td><td style="padding:6px 8px;font-size:10px;color:#555;">| DX | 구분 | BIM | | :--- | :---: | ---: | | **BIM << DX** (Engineering + Management 통합) | **범위** | *</td></tr>
|
||||
<tr style="background:#f8fafc;"><td style="padding:6px 8px;text-align:center;">6</td><td style="padding:6px 8px;font-weight:700;">핵심 요약</td><td style="padding:6px 8px;color:#7c3aed;">결론</td><td style="padding:6px 8px;">conclusion</td><td style="padding:6px 8px;font-size:10px;">BIM은 건설산업의 디지털전환(DX)을 수행하는 과정에서 **가장 기초가 되는 일부분**이다</td><td style="padding:6px 8px;font-size:10px;color:#555;">BIM은 건설산업의 디지털전환(DX)을 수행하는 과정에서 **가장 기초가 되는 일부분**이다</td></tr>
|
||||
</table></body></html>
|
||||
7
docs/run-001/05-execution/steps/stage_2.html
Normal file
7
docs/run-001/05-execution/steps/stage_2.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<!DOCTYPE html><html><head><meta charset="UTF-8">
|
||||
<style>*{margin:0;padding:0;box-sizing:border-box;}body{background:#e5e5e5;padding:10px;font-family:sans-serif;word-break:keep-all;}</style>
|
||||
</head><body>
|
||||
<div style="font-size:16px;font-weight:bold;margin-bottom:8px;">Stage 2: HTML 생성 결과</div>
|
||||
<div style="font-size:11px;color:#666;margin-bottom:12px;">영역별로 생성된 HTML (미리보기) + 서브 컨테이너 레이아웃</div>
|
||||
<div style="margin-bottom:12px;"><div style="font-size:13px;font-weight:700;color:#2563eb;margin-bottom:4px;">본심 (body_html)</div><pre style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:4px;padding:8px;font-size:10px;max-height:200px;overflow:auto;white-space:pre-wrap;"><div style="width:100%; height:100%; box-sizing:border-box; font-family:'Segoe UI',sans-serif; color:#0f172a; display:flex; flex-direction:column; gap:8px;"><div style="background:linear-gradient(135deg,#fff7ed 0%,#ffedd5 100%); border:1px solid #fdba74; border-radius:12px; padding:10px 12px; display:grid; grid-template-columns:1fr 1fr; gap:12px;"><div><div style="font-size:12px; font-weight:800; color:#c2410c; margin-bottom:6px;">용어의 혼용</div><ul style="font-size:10px; line-height:1.6; color:#7c...</pre></div><div style="margin-bottom:12px;"><div style="font-size:13px;font-weight:700;color:#16a34a;margin-bottom:4px;">첨부 (sidebar_html)</div><pre style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:4px;padding:8px;font-size:10px;max-height:200px;overflow:auto;white-space:pre-wrap;"><div style="width:100%; height:100%; box-sizing:border-box; font-family:'Segoe UI',sans-serif; display:flex; flex-direction:column; gap:8px;"><div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:12px; padding:10px 12px;"><div style="font-size:12px; font-weight:800; color:#1e293b; margin-bottom:8px;">용어 정의</div><div style="display:flex; flex-direction:column; gap:8px;"><div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:10px; padding:10px 12px;"><div style="...</pre></div><div style="margin-bottom:12px;"><div style="font-size:13px;font-weight:700;color:#7c3aed;margin-bottom:4px;">결론 (footer_html)</div><pre style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:4px;padding:8px;font-size:10px;max-height:200px;overflow:auto;white-space:pre-wrap;"><div style="background:linear-gradient(135deg, #006aff 0%, #00aaff 100%); border-radius:10px; padding:10px 20px; text-align:center; color:#ffffff; width:100%; height:52px; display:flex; align-items:center; justify-content:center; box-sizing:border-box;"><div style="font-size:12px; font-weight:800; line-height:1.35;">BIM은 건설산업의 디지털전환(DX)을 수행하는 과정에서 가장 기초가 되는 일부분이다</div></div></pre></div><div style="margin-bottom:12px;"><div style="font-size:13px;font-weight:700;color:#333;margin-bottom:4px;">reasoning (reasoning)</div><pre style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:4px;padding:8px;font-size:10px;max-height:200px;overflow:auto;white-space:pre-wrap;">retry regrouping by content importance: intro(problem+evidence), body(relation+comparison), sidebar(definitions), widths 66%/34%</pre></div>
|
||||
</body></html>
|
||||
5
docs/run-001/05-execution/steps/stage_3.html
Normal file
5
docs/run-001/05-execution/steps/stage_3.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE html><html><head><meta charset="UTF-8">
|
||||
<style>body{font-family:sans-serif;padding:20px;}</style></head><body>
|
||||
<h2>Stage 3: 렌더링 조립</h2>
|
||||
<p><a href="../final.html" style="font-size:18px;">final.html 열기 →</a></p>
|
||||
</body></html>
|
||||
12
docs/run-001/05-execution/steps/stage_4.html
Normal file
12
docs/run-001/05-execution/steps/stage_4.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html><html><head><meta charset="UTF-8">
|
||||
<style>*{margin:0;padding:0;box-sizing:border-box;}body{background:#e5e5e5;padding:10px;font-family:sans-serif;word-break:keep-all;}</style>
|
||||
</head><body>
|
||||
<div style="font-size:16px;font-weight:bold;margin-bottom:8px;">Stage 4: 품질 게이트</div>
|
||||
<div style="font-size:24px;font-weight:900;color:#dc2626;margin-bottom:12px;">품질 점수: 60</div>
|
||||
<div style="font-size:12px;color:#555;margin-bottom:4px;">슬라이드: clientHeight=720px, scrollHeight=720px, overflow=False</div>
|
||||
<table style="border-collapse:collapse;font-size:12px;width:100%;max-width:600px;margin-top:8px;">
|
||||
<tr style="background:#1e293b;color:white;"><th style="padding:8px;">영역</th><th style="padding:8px;">clientH</th><th style="padding:8px;">scrollH</th><th style="padding:8px;">excess</th></tr><tr style="background:#fee2e2;"><td style="padding:6px 8px;">❌ body</td><td style="padding:6px 8px;">483px</td><td style="padding:6px 8px;">561px</td><td style="padding:6px 8px;">+78px</td></tr>
|
||||
<tr style="background:#f0fdf4;"><td style="padding:6px 8px;">✅ footer</td><td style="padding:6px 8px;">52px</td><td style="padding:6px 8px;">52px</td><td style="padding:6px 8px;">+0px</td></tr>
|
||||
<tr style="background:#f0fdf4;"><td style="padding:6px 8px;">✅ sidebar</td><td style="padding:6px 8px;">483px</td><td style="padding:6px 8px;">483px</td><td style="padding:6px 8px;">+0px</td></tr>
|
||||
</table>
|
||||
</body></html>
|
||||
15
docs/run-001/05-execution/steps/step0_topics.html
Normal file
15
docs/run-001/05-execution/steps/step0_topics.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html><html><head><meta charset="UTF-8">
|
||||
<style>*{margin:0;padding:0;box-sizing:border-box;}body{background:#e5e5e5;padding:10px;font-family:sans-serif;word-break:keep-all;}</style>
|
||||
</head><body>
|
||||
<div style="font-size:16px;font-weight:bold;margin-bottom:8px;">Step 0: Kei 꼭지 (Stage 1A/1B)</div>
|
||||
<table style="border-collapse:collapse;font-size:12px;width:100%;max-width:900px;">
|
||||
<tr style="background:#1e293b;color:white;"><th style="padding:8px;">ID</th><th style="padding:8px;">제목</th>
|
||||
<th style="padding:8px;">purpose</th><th style="padding:8px;">layer</th><th style="padding:8px;">relation_type</th>
|
||||
<th style="padding:8px;">영역</th></tr><tr style="background:#fff;"><td style="padding:6px 8px;text-align:center;">1</td><td style="padding:6px 8px;font-weight:700;">용어의 혼용</td><td style="padding:6px 8px;">문제제기</td><td style="padding:6px 8px;">intro</td><td style="padding:6px 8px;">cause_effect</td><td style="padding:6px 8px;color:#dc2626;font-weight:700;">배경</td></tr>
|
||||
<tr style="background:#f8fafc;"><td style="padding:6px 8px;text-align:center;">2</td><td style="padding:6px 8px;font-weight:700;">용어 정의</td><td style="padding:6px 8px;">정의정립</td><td style="padding:6px 8px;">core</td><td style="padding:6px 8px;">definition</td><td style="padding:6px 8px;color:#2563eb;font-weight:700;">본심</td></tr>
|
||||
<tr style="background:#fff;"><td style="padding:6px 8px;text-align:center;">3</td><td style="padding:6px 8px;font-weight:700;">용어간 상호관계</td><td style="padding:6px 8px;">관계설명</td><td style="padding:6px 8px;">core</td><td style="padding:6px 8px;">hierarchy</td><td style="padding:6px 8px;color:#2563eb;font-weight:700;">본심</td></tr>
|
||||
<tr style="background:#f8fafc;"><td style="padding:6px 8px;text-align:center;">4</td><td style="padding:6px 8px;font-weight:700;">혼용 대표 사례</td><td style="padding:6px 8px;">근거사례</td><td style="padding:6px 8px;">supporting</td><td style="padding:6px 8px;">evidence</td><td style="padding:6px 8px;color:#dc2626;font-weight:700;">배경</td></tr>
|
||||
<tr style="background:#fff;"><td style="padding:6px 8px;text-align:center;">5</td><td style="padding:6px 8px;font-weight:700;">DX와 BIM의 구분</td><td style="padding:6px 8px;">비교근거</td><td style="padding:6px 8px;">supporting</td><td style="padding:6px 8px;">comparison</td><td style="padding:6px 8px;color:#16a34a;font-weight:700;">첨부</td></tr>
|
||||
<tr style="background:#f8fafc;"><td style="padding:6px 8px;text-align:center;">6</td><td style="padding:6px 8px;font-weight:700;">핵심 요약</td><td style="padding:6px 8px;">결론강조</td><td style="padding:6px 8px;">conclusion</td><td style="padding:6px 8px;">none</td><td style="padding:6px 8px;color:#7c3aed;font-weight:700;">결론</td></tr>
|
||||
</table>
|
||||
<div style="margin-top:12px;font-size:12px;color:#555;"><b>페이지 구조:</b><br>배경: topic_ids=[1, 4], weight=0.22<br>본심: topic_ids=[2, 3], weight=0.5<br>첨부: topic_ids=[5], weight=0.18<br>결론: topic_ids=[6], weight=0.1</div></body></html>
|
||||
16
docs/run-001/05-execution/steps/step1_containers.html
Normal file
16
docs/run-001/05-execution/steps/step1_containers.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html><html><head><meta charset="UTF-8">
|
||||
<style>
|
||||
*{margin:0;padding:0;box-sizing:border-box;}
|
||||
body{background:#e5e5e5;padding:10px;font-family:'Pretendard Variable','Noto Sans KR',sans-serif;word-break:keep-all;}
|
||||
.bl{display:flex;gap:0;margin-bottom:2px;}.bl-m{flex-shrink:0;width:1em;}.bl-t{flex:1;}
|
||||
</style></head><body>
|
||||
<div style="font-size:16px;font-weight:bold;margin-bottom:4px;">Step 1: 빈 컨테이너 (Stage 1.5a)</div>
|
||||
<div style="font-size:11px;color:#666;margin-bottom:8px;">비율 64:36</div>
|
||||
<div style="width:1280px;height:720px;background:white;position:relative;border:1px solid #ccc;">
|
||||
<div style="position:absolute;left:40px;top:40px;width:1200px;height:66px;background:#f8fafc;border-bottom:3px solid #2563eb;display:flex;align-items:center;padding:0 20px;font-size:22px;font-weight:900;color:#1e293b;">건설산업 DX의 올바른 이해</div>
|
||||
<div style="position:absolute;left:40px;top:126px;width:768px;height:143px;border:2px solid #dc2626;border-radius:6px;background:#dc262608;overflow:hidden;"><div style="text-align:center;margin-top:56px;"><b style="color:#dc2626;font-size:13px;">배경</b><br><span style="color:#888;font-size:10px;">768x143px / font:12.0px</span></div></div>
|
||||
<div style="position:absolute;left:40px;top:277px;width:768px;height:326px;border:2px solid #2563eb;border-radius:6px;background:#2563eb08;overflow:hidden;"><div style="text-align:center;margin-top:148px;"><b style="color:#2563eb;font-size:13px;">본심</b><br><span style="color:#888;font-size:10px;">768x326px / font:12.0px</span></div></div>
|
||||
<div style="position:absolute;left:828px;top:126px;width:412px;height:490px;border:2px solid #16a34a;border-radius:6px;background:#16a34a08;overflow:hidden;"><div style="text-align:center;margin-top:230px;"><b style="color:#16a34a;font-size:13px;">첨부</b><br><span style="color:#888;font-size:10px;">412x490px / font:11.0px</span></div></div>
|
||||
<div style="position:absolute;left:40px;top:636px;width:1200px;height:60px;border:2px solid #7c3aed;border-radius:6px;background:#7c3aed08;overflow:hidden;"><div style="text-align:center;margin-top:15px;"><b style="color:#7c3aed;font-size:13px;">결론</b><br><span style="color:#888;font-size:10px;">1200x60px / font:14.0px</span></div></div>
|
||||
|
||||
</div></body></html>
|
||||
16
docs/run-001/05-execution/steps/step1b_content.html
Normal file
16
docs/run-001/05-execution/steps/step1b_content.html
Normal file
File diff suppressed because one or more lines are too long
16
docs/run-001/05-execution/steps/step2_blocks.html
Normal file
16
docs/run-001/05-execution/steps/step2_blocks.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html><html><head><meta charset="UTF-8">
|
||||
<style>
|
||||
*{margin:0;padding:0;box-sizing:border-box;}
|
||||
body{background:#e5e5e5;padding:10px;font-family:'Pretendard Variable','Noto Sans KR',sans-serif;word-break:keep-all;}
|
||||
.bl{display:flex;gap:0;margin-bottom:2px;}.bl-m{flex-shrink:0;width:1em;}.bl-t{flex:1;}
|
||||
</style></head><body>
|
||||
<div style="font-size:16px;font-weight:bold;margin-bottom:4px;">Step 2: 블록 선택 (Stage 1.7)</div>
|
||||
<div style="font-size:11px;color:#666;margin-bottom:8px;">layer 기반 주종 판단. 컨테이너 위에 블록 표시.</div>
|
||||
<div style="width:1280px;height:720px;background:white;position:relative;border:1px solid #ccc;">
|
||||
<div style="position:absolute;left:40px;top:40px;width:1200px;height:66px;background:#f8fafc;border-bottom:3px solid #2563eb;display:flex;align-items:center;padding:0 20px;font-size:22px;font-weight:900;color:#1e293b;">건설산업 DX의 올바른 이해</div>
|
||||
<div style="position:absolute;left:40px;top:126px;width:768px;height:143px;border:2px solid #dc2626;border-radius:6px;background:#dc262608;overflow:hidden;"><div style="padding:6px 10px;"><div style="font-size:10px;color:#dc2626;font-weight:700;margin-bottom:4px;">배경 (768x143px)</div><div style="font-size:11px;margin-bottom:2px;"><b>quote-big-mark</b> (default) <span style="color:#888;font-size:9px;">default</span></div></div></div>
|
||||
<div style="position:absolute;left:40px;top:277px;width:768px;height:326px;border:2px solid #2563eb;border-radius:6px;background:#2563eb08;overflow:hidden;"><div style="padding:6px 10px;"><div style="font-size:10px;color:#2563eb;font-weight:700;margin-bottom:4px;">본심 (768x326px)</div><div style="font-size:11px;margin-bottom:2px;"><b>card-dark-overlay</b> (default) <span style="color:#888;font-size:9px;">default</span></div><div style="font-size:11px;margin-bottom:2px;"><b>circle-gradient</b> (default) <span style="color:#888;font-size:9px;">default</span></div></div></div>
|
||||
<div style="position:absolute;left:828px;top:126px;width:412px;height:490px;border:2px solid #16a34a;border-radius:6px;background:#16a34a08;overflow:hidden;"><div style="padding:6px 10px;"><div style="font-size:10px;color:#16a34a;font-weight:700;margin-bottom:4px;">첨부 (412x490px)</div><div style="font-size:11px;margin-bottom:2px;"><b>card-image-3col</b> (default) <span style="color:#888;font-size:9px;">default</span></div></div></div>
|
||||
<div style="position:absolute;left:40px;top:636px;width:1200px;height:60px;border:2px solid #7c3aed;border-radius:6px;background:#7c3aed08;overflow:hidden;"><div style="padding:6px 10px;"><div style="font-size:10px;color:#7c3aed;font-weight:700;margin-bottom:4px;">결론 (1200x60px)</div><div style="font-size:11px;margin-bottom:2px;"><b>banner-gradient</b> (default) <span style="color:#888;font-size:9px;">default</span></div></div></div>
|
||||
|
||||
</div></body></html>
|
||||
5
docs/run-001/05-execution/steps/step4_final.html
Normal file
5
docs/run-001/05-execution/steps/step4_final.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE html><html><head><meta charset="UTF-8">
|
||||
<style>body{font-family:sans-serif;padding:20px;}</style></head><body>
|
||||
<h2>Step 4: 최종 결과물 (Stage 2+3)</h2>
|
||||
<p><a href="../final.html" style="font-size:18px;">final.html 열기 →</a></p>
|
||||
</body></html>
|
||||
@@ -7,12 +7,12 @@
|
||||
|
||||
## Validation Summary
|
||||
- 실행 경로 검증: 통과
|
||||
- 렌더링/측정 검증: 통과
|
||||
- 렌더링/측정 검증: 실패
|
||||
- 최종 품질 판정: 재작업 필요
|
||||
|
||||
## Render Gates
|
||||
- slide overflow: False
|
||||
- body: overflowed=False excess_px=0 block_count=0
|
||||
- body: overflowed=True excess_px=78 block_count=0
|
||||
- sidebar: overflowed=False excess_px=0 block_count=0
|
||||
- footer: overflowed=False excess_px=0 block_count=0
|
||||
|
||||
@@ -30,26 +30,26 @@
|
||||
"body": {
|
||||
"block_count": 0,
|
||||
"blocks": [],
|
||||
"clientHeight": 474,
|
||||
"excess_px": 0,
|
||||
"overflowed": false,
|
||||
"scrollHeight": 474
|
||||
"clientHeight": 483,
|
||||
"excess_px": 78,
|
||||
"overflowed": true,
|
||||
"scrollHeight": 561
|
||||
},
|
||||
"footer": {
|
||||
"block_count": 0,
|
||||
"blocks": [],
|
||||
"clientHeight": 56,
|
||||
"clientHeight": 52,
|
||||
"excess_px": 0,
|
||||
"overflowed": false,
|
||||
"scrollHeight": 56
|
||||
"scrollHeight": 52
|
||||
},
|
||||
"sidebar": {
|
||||
"block_count": 0,
|
||||
"blocks": [],
|
||||
"clientHeight": 474,
|
||||
"clientHeight": 483,
|
||||
"excess_px": 0,
|
||||
"overflowed": false,
|
||||
"scrollHeight": 474
|
||||
"scrollHeight": 483
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,13 @@
|
||||
- 판정: `revise`
|
||||
|
||||
## Failure Classification
|
||||
- Verify-ComparisonVisible
|
||||
- Verify-DesignNarrative
|
||||
- Verify-DesignStructure
|
||||
- Verify-RenderZone
|
||||
|
||||
## Next Action
|
||||
1. 원문 주요 소제목과 읽기 순서가 유지되도록 본문 서사를 재구성한다.
|
||||
1. overflow가 발생한 zone(body)의 content budget, block 수, typography를 재조정한다.
|
||||
2. 비교 핵심 4축(범위, 프로세스, 성과품, 확장성)을 화면에 바로 보이는 요약 블록으로 강제한다.
|
||||
3. 핵심 관계를 설명하는 시각적 관계도 블록을 본문 중심 구조로 유지한다.
|
||||
4. 원문 주요 소제목과 읽기 순서가 유지되도록 본문 서사를 재구성한다.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
실행 요약
|
||||
- iteration 1 기준으로 최종 산출물과 측정 결과를 다시 검증했다.
|
||||
- slide overflow: False
|
||||
- zone overflow: 없음
|
||||
- zone overflow: body
|
||||
- 최종 판정은 `revise`이다.
|
||||
|
||||
산출물 경로
|
||||
@@ -12,9 +12,12 @@
|
||||
|
||||
KPI / 판정 결과
|
||||
- 판정: revise
|
||||
- 실패 분류: Verify-DesignNarrative
|
||||
- 실패 분류: Verify-ComparisonVisible, Verify-DesignNarrative, Verify-DesignStructure, Verify-RenderZone
|
||||
|
||||
수정 액션
|
||||
- overflow가 발생한 zone(body)의 content budget, block 수, typography를 재조정한다.
|
||||
- 비교 핵심 4축(범위, 프로세스, 성과품, 확장성)을 화면에 바로 보이는 요약 블록으로 강제한다.
|
||||
- 핵심 관계를 설명하는 시각적 관계도 블록을 본문 중심 구조로 유지한다.
|
||||
- 원문 주요 소제목과 읽기 순서가 유지되도록 본문 서사를 재구성한다.
|
||||
|
||||
다음 단계 전달물
|
||||
|
||||
@@ -9,12 +9,16 @@ import sys
|
||||
from pathlib import Path
|
||||
|
||||
DESIGN_AGENT_ROOT = Path(r'D:\ad-hoc\kei\design_agent')
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
LOCAL_TEMPLATES_DIR = REPO_ROOT / 'templates'
|
||||
if str(DESIGN_AGENT_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(DESIGN_AGENT_ROOT))
|
||||
|
||||
import src.block_reference as block_reference_module
|
||||
from src.block_reference import select_and_generate_references
|
||||
from src.config import settings
|
||||
from src.content_verifier import generate_with_retry
|
||||
import src.design_director as design_director_module
|
||||
import src.html_generator as html_generator
|
||||
from src.design_director import LAYOUT_PRESETS, select_preset
|
||||
from src.image_utils import embed_images, get_image_sizes
|
||||
@@ -31,6 +35,7 @@ from src.pipeline_context import (
|
||||
Topic,
|
||||
create_context,
|
||||
)
|
||||
import src.renderer as renderer_module
|
||||
from src.renderer import render_slide_from_html
|
||||
from src.slide_measurer import capture_slide_screenshot, measure_rendered_heights
|
||||
|
||||
@@ -39,6 +44,19 @@ if not hasattr(html_generator, 'SIDEBAR_PROMPT') and hasattr(html_generator, '_L
|
||||
if not hasattr(html_generator, 'FOOTER_PROMPT') and hasattr(html_generator, '_LEGACY_FOOTER_PROMPT'):
|
||||
html_generator.FOOTER_PROMPT = html_generator._LEGACY_FOOTER_PROMPT
|
||||
|
||||
if LOCAL_TEMPLATES_DIR.exists():
|
||||
block_reference_module.TEMPLATES_DIR = LOCAL_TEMPLATES_DIR
|
||||
block_reference_module._jinja_env = None
|
||||
renderer_module.TEMPLATES_DIR = LOCAL_TEMPLATES_DIR
|
||||
renderer_module.CATALOG_PATH = LOCAL_TEMPLATES_DIR / 'catalog.yaml'
|
||||
renderer_module._CATALOG_MAP = None
|
||||
renderer_module._CATALOG_VARIANT_MAP = None
|
||||
renderer_module._env = None
|
||||
if hasattr(design_director_module, '_CATALOG_CACHE'):
|
||||
design_director_module._CATALOG_CACHE = None
|
||||
if hasattr(design_director_module, '_BLOCK_IDS_CACHE'):
|
||||
design_director_module._BLOCK_IDS_CACHE = None
|
||||
|
||||
from src.space_allocator import (
|
||||
ContainerSpec as LegacyContainerSpec,
|
||||
calculate_container_specs,
|
||||
@@ -290,127 +308,304 @@ def _extract_multiple_sentences(text: str, keywords: list[str], fallback: str, l
|
||||
return fallback
|
||||
|
||||
|
||||
def _plain_text(value: str) -> str:
|
||||
text = value or ''
|
||||
text = re.sub(r'<br\s*/?>', '\n', text, flags=re.I)
|
||||
text = re.sub(r'<[^>]+>', ' ', text)
|
||||
text = text.replace('**', '').replace('*', ' ')
|
||||
text = text.replace('<', '<').replace('>', '>').replace('&', '&')
|
||||
text = re.sub(r'!\[[^\]]*\]\([^\)]*\)', ' ', text)
|
||||
text = re.sub(r'\[[^\]]+\]\([^\)]*\)', ' ', text)
|
||||
text = re.sub(r'\s+', ' ', text).strip()
|
||||
return text
|
||||
|
||||
def _markdown_section(text: str, start_marker: str, end_marker: str | None = None) -> str:
|
||||
start = text.find(start_marker)
|
||||
if start == -1:
|
||||
return ''
|
||||
chunk = text[start + len(start_marker):]
|
||||
if end_marker:
|
||||
end = chunk.find(end_marker)
|
||||
if end != -1:
|
||||
chunk = chunk[:end]
|
||||
return chunk.strip()
|
||||
|
||||
|
||||
def _content_after_frontmatter(raw: str) -> str:
|
||||
if raw.startswith('---'):
|
||||
parts = raw.split('---', 2)
|
||||
if len(parts) == 3:
|
||||
return parts[2].strip()
|
||||
return raw
|
||||
|
||||
|
||||
def _content_after_frontmatter(raw: str) -> str:
|
||||
if raw.startswith('---'):
|
||||
parts = raw.split('---', 2)
|
||||
if len(parts) == 3:
|
||||
return parts[2].strip()
|
||||
return raw
|
||||
|
||||
|
||||
def _problem_bullets_from_raw(raw: str) -> list[str]:
|
||||
content = _content_after_frontmatter(raw)
|
||||
before_sep = content.split('<br/>\n---', 1)[0]
|
||||
bullets = []
|
||||
for line in before_sep.splitlines():
|
||||
stripped = line.strip()
|
||||
if stripped.startswith('* ') and not stripped.startswith('* **'):
|
||||
bullets.append(_plain_text(stripped[2:]))
|
||||
return [b for b in bullets if b]
|
||||
|
||||
|
||||
def _details_blocks(raw: str) -> list[str]:
|
||||
return re.findall(r'<details>(.*?)</details>', raw, flags=re.S)
|
||||
|
||||
|
||||
def _evidence_bullets_from_raw(raw: str) -> list[str]:
|
||||
blocks = _details_blocks(raw)
|
||||
if not blocks:
|
||||
return []
|
||||
bullets = []
|
||||
for line in blocks[0].splitlines():
|
||||
stripped = line.strip()
|
||||
if stripped.startswith('* '):
|
||||
bullets.append(_plain_text(stripped[2:]))
|
||||
return [b for b in bullets if b]
|
||||
|
||||
|
||||
def _definition_sections_from_raw(raw: str) -> list[dict[str, str]]:
|
||||
match = re.search(r'##\s*1\.[^\n]*\n(.*?)##\s*2\.', raw, flags=re.S)
|
||||
block = match.group(1) if match else ''
|
||||
sections: list[dict[str, str]] = []
|
||||
current_title = None
|
||||
current_lines: list[str] = []
|
||||
for line in block.splitlines():
|
||||
stripped = line.strip()
|
||||
if stripped.startswith('* **'):
|
||||
if current_title and current_lines:
|
||||
sections.append({'title': _plain_text(current_title), 'body': _plain_text(' '.join(current_lines))})
|
||||
current_title = stripped[2:]
|
||||
current_lines = []
|
||||
elif stripped.startswith('* '):
|
||||
current_lines.append(stripped[2:])
|
||||
if current_title and current_lines:
|
||||
sections.append({'title': _plain_text(current_title), 'body': _plain_text(' '.join(current_lines))})
|
||||
return sections
|
||||
|
||||
|
||||
def _relation_bullets_from_raw(raw: str) -> list[str]:
|
||||
start = re.search(r'##\s*2\.[^\n]*\n', raw)
|
||||
if not start:
|
||||
return []
|
||||
block = raw[start.end():].split('<details>', 1)[0]
|
||||
bullets = []
|
||||
for line in block.splitlines():
|
||||
stripped = line.strip()
|
||||
if stripped.startswith('* '):
|
||||
content = _plain_text(stripped[2:])
|
||||
if content and '[??' not in content:
|
||||
bullets.append(content)
|
||||
return bullets
|
||||
|
||||
|
||||
def _extract_image_src_from_raw(raw: str) -> str:
|
||||
m = re.search(r'!\[[^\]]*\]\(([^\)]+)\)', raw)
|
||||
return m.group(1).strip() if m else ''
|
||||
|
||||
|
||||
def _extract_caption_from_raw(raw: str) -> str:
|
||||
m = re.search(r'\*\[[^\]]+\][^*]+\*', raw)
|
||||
if m:
|
||||
return _plain_text(m.group(0))
|
||||
return 'relation diagram'
|
||||
|
||||
|
||||
def _parse_comparison_rows_from_raw(raw: str) -> list[tuple[str, str, str]]:
|
||||
blocks = _details_blocks(raw)
|
||||
if len(blocks) < 2:
|
||||
return []
|
||||
rows: list[tuple[str, str, str]] = []
|
||||
for line in blocks[1].splitlines():
|
||||
stripped = line.strip()
|
||||
if not stripped.startswith('|'):
|
||||
continue
|
||||
parts = [p.strip() for p in stripped.strip('|').split('|')]
|
||||
if len(parts) != 3:
|
||||
continue
|
||||
if parts[0].startswith(':---') or parts[1].startswith(':---') or parts[2].startswith('---'):
|
||||
continue
|
||||
dx, axis, bim = (_plain_text(parts[0]), _plain_text(parts[1]), _plain_text(parts[2]))
|
||||
if dx == 'DX' and bim == 'BIM':
|
||||
continue
|
||||
rows.append((axis, dx, bim))
|
||||
return rows
|
||||
|
||||
|
||||
def _conclusion_from_raw(raw: str) -> str:
|
||||
m = re.search(r':::note\[[^\]]+\](.*?):::', raw, flags=re.S)
|
||||
block = m.group(1) if m else ''
|
||||
for line in block.splitlines():
|
||||
stripped = line.strip()
|
||||
if stripped.startswith('* '):
|
||||
return _plain_text(stripped[2:])
|
||||
return _plain_text(block)
|
||||
|
||||
|
||||
def _relation_visual(image_src: str, caption: str) -> str:
|
||||
if image_src:
|
||||
return f'<img src="{image_src}" alt="{caption}" style="width:100%; height:220px; object-fit:contain; border:1px solid #dbeafe; border-radius:12px; background:#f8fafc; padding:10px;" />'
|
||||
return (
|
||||
'<div style="width:100%; height:220px; border:1px solid #dbeafe; border-radius:12px; background:#f8fafc; padding:10px; display:flex; align-items:center; justify-content:center;">'
|
||||
'<svg viewBox="0 0 320 220" width="100%" height="100%" aria-label="relation diagram">'
|
||||
'<circle cx="150" cy="110" r="82" fill="#1d4ed8" opacity="0.95"></circle>'
|
||||
'<text x="150" y="102" text-anchor="middle" font-size="12" fill="#dbeafe">Digital</text>'
|
||||
'<text x="150" y="122" text-anchor="middle" font-size="28" font-weight="800" fill="#ffffff">DX</text>'
|
||||
'<circle cx="92" cy="130" r="38" fill="#f59e0b" opacity="0.95"></circle>'
|
||||
'<text x="92" y="136" text-anchor="middle" font-size="18" font-weight="800" fill="#ffffff">BIM</text>'
|
||||
'<circle cx="205" cy="92" r="34" fill="#06b6d4" opacity="0.95"></circle>'
|
||||
'<text x="205" y="98" text-anchor="middle" font-size="16" font-weight="800" fill="#ffffff">GIS</text>'
|
||||
'<circle cx="196" cy="154" r="32" fill="#f97316" opacity="0.95"></circle>'
|
||||
'<text x="196" y="158" text-anchor="middle" font-size="11" font-weight="800" fill="#ffffff">Digital Twin</text>'
|
||||
'</svg></div>'
|
||||
)
|
||||
|
||||
|
||||
|
||||
def _build_stage2_retry_html(ctx: PipelineContext, retry_plan: dict) -> dict:
|
||||
title = ctx.analysis.title
|
||||
raw = ctx.raw_content or ''
|
||||
|
||||
problem_topic = _topic(ctx, 1)
|
||||
evidence_topic = _topic(ctx, 4)
|
||||
definitions_topic = _topic(ctx, 2)
|
||||
relation_topic = _topic(ctx, 3)
|
||||
evidence_topic = _topic(ctx, 4)
|
||||
comparison_topic = _topic(ctx, 5)
|
||||
conclusion_topic = _topic(ctx, 6)
|
||||
dx_topic = _topic(ctx, 2)
|
||||
|
||||
problem_text = _trim_visible_copy(_prefer_source_text(problem_topic, '건설산업 디지털 전환 논의에서 DX와 BIM이 혼용되며 BIM 도입을 DX 완성으로 오인하는 문제가 발생하고 있다.'), floor=120, ceiling=260)
|
||||
relation_source = _prefer_source_text(relation_topic, 'DX와 GIS, BIM, Digital Twin의 관계를 시각적으로 드러낸다.')
|
||||
relation_text = _trim_visible_copy(relation_source, floor=110, ceiling=180)
|
||||
gis_line = _trim_visible_copy(_extract_sentence(relation_source, 'GIS', 'GIS는 공간 분석과 위치 기반 정보를 제공한다.'), floor=60, ceiling=140)
|
||||
bim_line = _trim_visible_copy(_extract_sentence(relation_source, 'BIM', 'BIM은 형상정보와 내용정보를 함께 다루는 핵심 인프라 기술이다.'), floor=60, ceiling=160)
|
||||
evidence_source = _prefer_source_text(evidence_topic, '정책 문서에서도 DX와 BIM이 혼용되며 이를 바로잡을 필요가 있다.')
|
||||
evidence_text = _trim_visible_copy(evidence_source, floor=90, ceiling=170)
|
||||
dx_source = _prefer_source_text(dx_topic, 'DX는 상위 개념이고 BIM은 이를 실행하는 핵심 기술이다.')
|
||||
dx_text = _trim_visible_copy(dx_source, floor=110, ceiling=220)
|
||||
compare_source = _prefer_source_text(comparison_topic, '범위·프로세스·성과품·확장성의 4개 비교축으로 DX와 BIM 차이를 짧고 직접적으로 보여준다.')
|
||||
compare_text = _trim_visible_copy(compare_source, floor=90, ceiling=120)
|
||||
conclusion_text = _trim_visible_copy(_prefer_source_text(conclusion_topic, '결론: BIM은 건설산업 DX를 수행하는 과정의 가장 기초가 되는 일부분이다.'), floor=70, ceiling=180)
|
||||
problem_title = problem_topic.title if problem_topic and problem_topic.title else 'DX와 BIM의 혼용 문제'
|
||||
dx_title = dx_topic.title if dx_topic and dx_topic.title else 'DX의 정의와 위치'
|
||||
relation_title = relation_topic.title if relation_topic and relation_topic.title else 'BIM과 핵심기술의 관계'
|
||||
comparison_title = comparison_topic.title if comparison_topic and comparison_topic.title else 'DX와 BIM 비교 핵심 포인트'
|
||||
evidence_title = evidence_topic.title if evidence_topic and evidence_topic.title else '정책 혼용 사례'
|
||||
problem_title = problem_topic.title if problem_topic and problem_topic.title else 'Problem'
|
||||
definitions_title = definitions_topic.title if definitions_topic and definitions_topic.title else 'Definitions'
|
||||
relation_title = relation_topic.title if relation_topic and relation_topic.title else 'Relationship'
|
||||
evidence_title = evidence_topic.title if evidence_topic and evidence_topic.title else 'Evidence'
|
||||
comparison_title = comparison_topic.title if comparison_topic and comparison_topic.title else 'Comparison'
|
||||
|
||||
body_html = f"""
|
||||
<div style="width:100%; height:100%; box-sizing:border-box; font-family:'Segoe UI',sans-serif; color:#0f172a; display:flex; flex-direction:column; gap:6px;">
|
||||
<div style="background:linear-gradient(135deg,#fff7ed 0%,#ffedd5 100%); border:1px solid #fdba74; border-radius:12px; padding:8px 10px;">
|
||||
<div style="font-size:11px; font-weight:800; color:#c2410c; margin-bottom:4px;">{problem_title}</div>
|
||||
<div style="font-size:10px; line-height:1.55; color:#7c2d12;">{problem_text}</div>
|
||||
</div>
|
||||
problem_bullets = _problem_bullets_from_raw(raw)[:2]
|
||||
evidence_bullets = _evidence_bullets_from_raw(raw)[:4]
|
||||
definition_sections = _definition_sections_from_raw(raw)[:3]
|
||||
relation_bullets = _relation_bullets_from_raw(raw)[:4]
|
||||
comparison_rows = _parse_comparison_rows_from_raw(raw)
|
||||
|
||||
<div class="relation-diagram-card" style="background:#ffffff; border:1px solid #cbd5e1; border-radius:14px; padding:14px 16px; box-sizing:border-box; display:flex; flex-direction:column; gap:6px;">
|
||||
<div style="display:flex; justify-content:space-between; align-items:flex-start; gap:12px;">
|
||||
<div>
|
||||
<div style="font-size:12px; font-weight:800; color:#1e40af; margin-bottom:4px;">{dx_title}</div>
|
||||
<div style="font-size:10px; line-height:1.55; color:#334155;">{dx_text}</div>
|
||||
</div>
|
||||
<div style="font-size:10px; color:#166534; background:#dcfce7; border:1px solid #86efac; border-radius:999px; padding:4px 8px; white-space:nowrap;">[그림 1] DX와 핵심기술간 상호관계</div>
|
||||
</div>
|
||||
preferred_axes = ['??', '????', '???', '???']
|
||||
picked_rows = [row for row in comparison_rows if row[0] in preferred_axes]
|
||||
if len(picked_rows) < 4:
|
||||
seen = {row[0] for row in picked_rows}
|
||||
for row in comparison_rows:
|
||||
if row[0] not in seen:
|
||||
picked_rows.append(row)
|
||||
seen.add(row[0])
|
||||
if len(picked_rows) >= 4:
|
||||
break
|
||||
picked_rows = picked_rows[:4]
|
||||
|
||||
<div style="display:grid; grid-template-columns:198px 1fr; gap:8px; align-items:start;">
|
||||
<div style="background:#f8fafc; border:1px solid #dbeafe; border-radius:14px; padding:10px; box-sizing:border-box;">
|
||||
<div style="display:flex; align-items:center; justify-content:center; gap:8px; margin-bottom:8px;">
|
||||
<div style="min-width:68px; text-align:center; background:#1d4ed8; color:#ffffff; border-radius:999px; padding:8px 12px; font-size:14px; font-weight:800;">DX</div>
|
||||
<div style="font-size:14px; color:#94a3b8;">→</div>
|
||||
</div>
|
||||
<div style="display:grid; grid-template-columns:1fr 1fr; gap:8px;">
|
||||
<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:10px; padding:8px; text-align:center; font-size:10px; font-weight:700;">GIS</div>
|
||||
<div style="background:#dbeafe; border:2px solid #3b82f6; border-radius:10px; padding:8px; text-align:center; font-size:10px; font-weight:800; color:#1d4ed8;">BIM</div>
|
||||
<div style="grid-column:1 / span 2; background:#ffffff; border:1px solid #cbd5e1; border-radius:10px; padding:8px; text-align:center; font-size:10px; font-weight:700;">Digital Twin</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex; flex-direction:column; gap:6px;">
|
||||
<div style="background:#f8fafc; border:1px solid #e2e8f0; border-radius:12px; padding:8px 10px;">
|
||||
<div style="font-size:11px; font-weight:800; color:#0f172a; margin-bottom:4px;">{relation_title}</div>
|
||||
<div style="font-size:10px; line-height:1.55; color:#334155;">{relation_text}</div>
|
||||
</div>
|
||||
<div style="display:grid; grid-template-columns:1fr 1fr; gap:8px;">
|
||||
<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:10px; padding:8px 9px;">
|
||||
<div style="font-size:10px; font-weight:800; color:#0f172a; margin-bottom:3px;">GIS 역할</div>
|
||||
<div style="font-size:8px; line-height:1.45; color:#475569;">{gis_line}</div>
|
||||
</div>
|
||||
<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:10px; padding:8px 9px;">
|
||||
<div style="font-size:10px; font-weight:800; color:#0f172a; margin-bottom:3px;">BIM 역할</div>
|
||||
<div style="font-size:8px; line-height:1.45; color:#475569;">{bim_line}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
image_src = _extract_image_src_from_raw(raw)
|
||||
if image_src and ctx.base_path:
|
||||
candidate = Path(ctx.base_path) / image_src.lstrip('/\\').replace('/', '\\')
|
||||
if not candidate.exists():
|
||||
image_src = ''
|
||||
else:
|
||||
image_src = ''
|
||||
image_caption = _extract_caption_from_raw(raw)
|
||||
conclusion_text = _conclusion_from_raw(raw)
|
||||
|
||||
<div class="comparison-summary-card" style="background:#eff6ff; border:1px solid #bfdbfe; border-radius:12px; padding:8px 9px; box-sizing:border-box; display:grid; grid-template-columns:96px 1fr; gap:7px;">
|
||||
<div>
|
||||
<div style="font-size:11px; font-weight:800; color:#1d4ed8; margin-bottom:4px;">{comparison_title}</div>
|
||||
<div style="font-size:8px; line-height:1.45; color:#475569;">{compare_text}</div>
|
||||
</div>
|
||||
<div style="display:grid; grid-template-columns:1fr 1fr; gap:8px; font-size:8px; line-height:1.35; color:#334155;">
|
||||
<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:10px; padding:7px 8px;"><span style="font-weight:800; color:#0f172a;">범위</span><br>DX는 BIM을 포함하는 상위 개념</div>
|
||||
<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:10px; padding:7px 8px;"><span style="font-weight:800; color:#0f172a;">프로세스</span><br>DX는 근본적 개선, BIM은 기존 2D 연장</div>
|
||||
<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:10px; padding:7px 8px;"><span style="font-weight:800; color:#0f172a;">성과품</span><br>DX는 공학 정보 연계, BIM은 3D 모델 중심</div>
|
||||
<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:10px; padding:7px 8px;"><span style="font-weight:800; color:#0f172a;">확장성</span><br>DX는 전 생애주기, BIM은 분야별 단절 위험</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
""".strip()
|
||||
intro_len = sum(len(x) for x in problem_bullets + evidence_bullets)
|
||||
defs_len = sum(len(s['body']) for s in definition_sections)
|
||||
relation_len = sum(len(x) for x in relation_bullets)
|
||||
sidebar_width = '34%' if defs_len >= relation_len else '31%'
|
||||
main_width = '66%' if defs_len >= relation_len else '69%'
|
||||
relation_visual_height = '210px' if intro_len > 320 else '230px'
|
||||
|
||||
sidebar_html = f"""
|
||||
<div style="width:100%; height:100%; box-sizing:border-box; font-family:'Segoe UI',sans-serif; display:flex; flex-direction:column; gap:6px;">
|
||||
<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:12px; padding:8px 10px;">
|
||||
<div style="font-size:11px; font-weight:800; color:#1e293b; margin-bottom:8px;">용어 정의</div>
|
||||
<div style="display:grid; grid-template-columns:72px 1fr; row-gap:8px; column-gap:10px; align-items:start; font-size:9px; line-height:1.5; color:#334155;">
|
||||
<div style="font-weight:800; color:#0f172a;">건설산업</div>
|
||||
<div>다양한 기술을 통합해 시설물을 구현하는 종합 산업</div>
|
||||
<div style="font-weight:800; color:#1d4ed8;">BIM</div>
|
||||
<div>3차원 모델 기반의 정보관리 도구이자 협업 인프라<br><span style="font-size:8px; color:#64748b;">출처: 국토교통부 BIM 기본지침</span></div>
|
||||
<div style="font-weight:800; color:#1d4ed8;">DX</div>
|
||||
<div>디지털 기술 기반으로 업무방식과 가치구조를 전환하는 상위 개념</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="background:#fff7ed; border:1px solid #fdba74; border-radius:12px; padding:8px 10px; box-sizing:border-box;">
|
||||
<div style="font-size:11px; font-weight:800; color:#c2410c; margin-bottom:5px;">{evidence_title}</div>
|
||||
<div style="font-size:10px; line-height:1.55; color:#7c2d12;">{evidence_text}</div>
|
||||
</div>
|
||||
</div>
|
||||
""".strip()
|
||||
problem_items_html = ''.join(
|
||||
f'<li style="margin-left:16px; margin-bottom:4px;">{_trim_visible_copy(item, floor=90, ceiling=220)}</li>'
|
||||
for item in problem_bullets
|
||||
)
|
||||
evidence_items_html = ''.join(
|
||||
f'<li style="margin-left:16px; margin-bottom:4px;">{_trim_visible_copy(item, floor=80, ceiling=180)}</li>'
|
||||
for item in evidence_bullets
|
||||
)
|
||||
relation_items_html = ''.join(
|
||||
f'<li style="margin-left:16px; margin-bottom:4px;">{_trim_visible_copy(item, floor=80, ceiling=210)}</li>'
|
||||
for item in relation_bullets
|
||||
)
|
||||
|
||||
footer_html = f"""
|
||||
<div style="background:linear-gradient(135deg, #006aff 0%, #00aaff 100%); border-radius:10px; padding:10px 20px; text-align:center; color:#ffffff; width:100%; height:52px; display:flex; align-items:center; justify-content:center; box-sizing:border-box;">
|
||||
<div style="font-size:12px; font-weight:800; line-height:1.35;">{conclusion_text}</div>
|
||||
</div>
|
||||
""".strip()
|
||||
definition_cards_html = ''
|
||||
for section in definition_sections:
|
||||
definition_cards_html += (
|
||||
'<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:10px; padding:10px 12px;">'
|
||||
f'<div style="font-size:11px; font-weight:800; color:#0f172a; margin-bottom:4px;">{section["title"]}</div>'
|
||||
f'<div style="font-size:9px; line-height:1.55; color:#334155;">{_trim_visible_copy(section["body"], floor=120, ceiling=250)}</div>'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
comparison_rows_html = ''
|
||||
for axis, dx, bim in picked_rows:
|
||||
comparison_rows_html += (
|
||||
'<tr>'
|
||||
f'<td style="border:1px solid #bfdbfe; padding:6px 8px; font-size:8px; line-height:1.4; color:#1e3a8a; width:42%;">{_trim_visible_copy(dx, floor=55, ceiling=120)}</td>'
|
||||
f'<td style="border:1px solid #bfdbfe; padding:6px 8px; font-size:8px; line-height:1.4; font-weight:800; color:#0f172a; width:16%; text-align:center; background:#eff6ff;">{axis}</td>'
|
||||
f'<td style="border:1px solid #bfdbfe; padding:6px 8px; font-size:8px; line-height:1.4; color:#334155; width:42%;">{_trim_visible_copy(bim, floor=55, ceiling=120)}</td>'
|
||||
'</tr>'
|
||||
)
|
||||
|
||||
intro_html = (
|
||||
'<div style="background:linear-gradient(135deg,#fff7ed 0%,#ffedd5 100%); border:1px solid #fdba74; border-radius:12px; padding:10px 12px; display:grid; grid-template-columns:1fr 1fr; gap:12px;">'
|
||||
f'<div><div style="font-size:12px; font-weight:800; color:#c2410c; margin-bottom:6px;">{problem_title}</div><ul style="font-size:10px; line-height:1.6; color:#7c2d12; padding-left:0; margin:0; list-style:disc;">{problem_items_html}</ul></div>'
|
||||
f'<div><div style="font-size:12px; font-weight:800; color:#9a3412; margin-bottom:6px;">{evidence_title}</div><ul style="font-size:9px; line-height:1.55; color:#7c2d12; padding-left:0; margin:0; list-style:disc;">{evidence_items_html}</ul></div>'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
relation_html = (
|
||||
f'<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:14px; padding:12px 14px; display:grid; grid-template-columns:280px 1fr; gap:12px;">'
|
||||
'<div style="display:flex; flex-direction:column; gap:6px;">'
|
||||
f'{_relation_visual(image_src, image_caption).replace("height:220px", f"height:{relation_visual_height}")}'
|
||||
f'<div style="font-size:9px; line-height:1.4; color:#166534; background:#dcfce7; border:1px solid #86efac; border-radius:999px; padding:4px 8px; text-align:center;">{image_caption}</div>'
|
||||
'</div>'
|
||||
'<div style="display:flex; flex-direction:column; gap:8px;">'
|
||||
f'<div style="font-size:12px; font-weight:800; color:#1e40af;">{relation_title}</div>'
|
||||
f'<ul style="font-size:10px; line-height:1.6; color:#334155; padding-left:0; margin:0; list-style:disc;">{relation_items_html}</ul>'
|
||||
'</div>'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
comparison_html = (
|
||||
'<div style="background:#eff6ff; border:1px solid #bfdbfe; border-radius:12px; padding:8px 10px;">'
|
||||
f'<div style="font-size:11px; font-weight:800; color:#1d4ed8; margin-bottom:6px;">{comparison_title}</div>'
|
||||
f'<table style="width:100%; border-collapse:collapse; table-layout:fixed;">{comparison_rows_html}</table>'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
body_html = (
|
||||
'<div style="width:100%; height:100%; box-sizing:border-box; font-family:\'Segoe UI\',sans-serif; color:#0f172a; display:flex; flex-direction:column; gap:8px;">'
|
||||
f'{intro_html}'
|
||||
f'{relation_html}'
|
||||
f'{comparison_html}'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
sidebar_html = (
|
||||
'<div style="width:100%; height:100%; box-sizing:border-box; font-family:\'Segoe UI\',sans-serif; display:flex; flex-direction:column; gap:8px;">'
|
||||
f'<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:12px; padding:10px 12px;"><div style="font-size:12px; font-weight:800; color:#1e293b; margin-bottom:8px;">{definitions_title}</div><div style="display:flex; flex-direction:column; gap:8px;">{definition_cards_html}</div></div>'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
footer_html = (
|
||||
'<div style="background:linear-gradient(135deg, #006aff 0%, #00aaff 100%); border-radius:10px; padding:10px 20px; text-align:center; color:#ffffff; width:100%; height:52px; display:flex; align-items:center; justify-content:center; box-sizing:border-box;">'
|
||||
f'<div style="font-size:12px; font-weight:800; line-height:1.35;">{conclusion_text}</div>'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
return {
|
||||
'body_html': body_html,
|
||||
'sidebar_html': sidebar_html,
|
||||
'footer_html': footer_html,
|
||||
'reasoning': f"stage_2 retry regeneration from rollback plan: {retry_plan.get('rollback_stage', 'stage_2')} with design-domain-guided slide composition",
|
||||
'reasoning': f"retry regrouping by content importance: intro(problem+evidence), body(relation+comparison), sidebar(definitions), widths {main_width}/{sidebar_width}",
|
||||
}
|
||||
|
||||
|
||||
|
||||
104
templates/blocks/INDEX.md
Normal file
104
templates/blocks/INDEX.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# 블록 라이브러리 인덱스 (38개)
|
||||
|
||||
디자인 팀장이 콘텐츠에 맞는 블록을 선택할 때 참조하는 라이브러리.
|
||||
각 카테고리 안에 변형이 여러 개 있으며, 콘텐츠 성격에 따라 적절한 변형을 선택한다.
|
||||
|
||||
**시각화(visuals/)는 SVG로 제작한다** — CSS/AI 이미지 금지.
|
||||
|
||||
---
|
||||
|
||||
## 📁 headers/ (5개) — 타이틀, 꼭지 헤더
|
||||
|
||||
| 파일 | 설명 | 언제 사용 |
|
||||
|------|------|---------|
|
||||
| `section-title-with-bg.html` | 배경 이미지 위 영문+한글 타이틀 (500px) | 페이지 맨 첫 화면, 배경 이미지 있을 때 |
|
||||
| `section-header-bar.html` | 파란 바 + 중앙 흰 제목 (컴팩트) | 섹션 시작 가볍게, 주제 전환 |
|
||||
| `topic-left-right.html` | 좌:파란 제목 + 우:설명 | 질문+답변 구조, 주장+근거 |
|
||||
| `topic-center.html` | 중앙 정렬 대제목 + 서브+설명 | 단독 강조, 주제 선언 |
|
||||
| `topic-numbered.html` | 번호 원형 + 제목 + 구분선 + 설명 | 순서 있는 꼭지 (1번, 2번, 3번) |
|
||||
|
||||
---
|
||||
|
||||
## 📁 cards/ (9개) — 카드 계열
|
||||
|
||||
| 파일 | 설명 | 언제 사용 |
|
||||
|------|------|---------|
|
||||
| `card-image-3col.html` | 이미지(160px) + 색상 제목 + 영문 + 불릿 (3열) | 단계별 설명에 이미지 핵심 |
|
||||
| `card-dark-overlay.html` | 다크 이미지 배경 + 흰 제목 + 짧은 설명 (3~5열) | 키워드 시각 강조, 임팩트 |
|
||||
| `card-tag-image.html` | 색상 태그 라벨 + 이미지 + 제목 + 설명 (3열) | 카테고리별 분류 (제조/건축/토목) |
|
||||
| `card-icon-desc.html` | 큰 이모지 아이콘 + 제목 + 설명 (2~4열) | 기능/특성/장점 아이콘 나열 |
|
||||
| `card-compare-3col.html` | 색상 헤더 카드 3열 + 불릿 | 3개 카테고리 비교 (상용/범용/전문) |
|
||||
| `card-step-vertical.html` | 좌 색상 마커 + 우 콘텐츠 (세로, 연결선) | 생애주기 단계별 (이미지+설명) |
|
||||
| `card-image-round.html` | 원형 이미지(140px) + 제목 + 설명 (2~3열) | 포트폴리오형, 비전/가치 |
|
||||
| `card-stat-number.html` | 큰 숫자(36px) + 단위 + 라벨 (2~4열) | KPI, 성과 수치, 비용 절감율 |
|
||||
| `card-numbered.html` | 색상 원형 번호 + 제목 + 설명 (세로) | 순서 있는 항목 (실행 단계, 조건) |
|
||||
|
||||
---
|
||||
|
||||
## 📁 tables/ (3개) — 표/비교 계열
|
||||
|
||||
| 파일 | 설명 | 언제 사용 |
|
||||
|------|------|---------|
|
||||
| `compare-3col-badge.html` | A \| VS배지 \| B 3단 비교 (행별) | 두 개념 다항목 비교 (BIM vs DX) |
|
||||
| `compare-2col-split.html` | 파란 헤더 좌/구분/우 + 행별 비교 | 두 기술 항목별 상세 비교 (GIS vs BIM) |
|
||||
| `table-simple-striped.html` | 남색 헤더 + 줄무늬 행. 범용 | 스펙표, 일정표, 수치 목록 |
|
||||
|
||||
---
|
||||
|
||||
## 📁 visuals/ (6개) — 시각 요소 (**SVG**)
|
||||
|
||||
**SVG 노하우:**
|
||||
- `<text>` = 원 좌표와 같은 공간 → 위치 100% 정확
|
||||
- `radialGradient`/`linearGradient` → 고급 그라데이션
|
||||
- `filter` → 글로우/그림자
|
||||
- 수학적 계산 (cos/sin) → N개 자동 배치 (Phase 2)
|
||||
- **AI 이미지로 시각화 만들면 안 됨** — 원 위치 맞출 수 없음
|
||||
|
||||
| 파일 | 설명 | 언제 사용 |
|
||||
|------|------|---------|
|
||||
| `venn-diagram.html` | **SVG premium** 벤 다이어그램 (그라데이션+글로우) | 포함 관계, 기술 융합 (**★단독 배치**) |
|
||||
| `circle-gradient.html` | 파란 그라데이션 원 + 중앙 텍스트 | 섹션 전환 키워드 강조 |
|
||||
| `compare-pill-pair.html` | 이중 테두리 둥근 박스 2개 + VS | 2개 개념 시각 대비 (표 위 헤더) |
|
||||
| `process-horizontal.html` | 파란 번호 원 + 카드 + → 화살표 (가로) | 논리적 프로세스 흐름 |
|
||||
| `flow-arrow-horizontal.html` | 색상 캡슐 + 화살표 (SVG, 컴팩트) | 기술 발전/전환 흐름 간결하게 |
|
||||
| `keyword-circle-row.html` | SVG 원형 안 큰 글자 + 라벨 + 설명 | 약어 풀이 (G-S-I-M) |
|
||||
|
||||
---
|
||||
|
||||
## 📁 emphasis/ (10개) — 강조, 인용, 결론
|
||||
|
||||
| 파일 | 설명 | 언제 사용 |
|
||||
|------|------|---------|
|
||||
| `quote-big-mark.html` | ❝❞ 큰따옴표 장식 + 인용+출처 | 임팩트 인용, 핵심 발언 |
|
||||
| `quote-question.html` | 파란 배경+테두리 + 큰 질문 텍스트 | 독자에게 질문, 전환점 |
|
||||
| `comparison-2col.html` | 좌 파란 vs 우 빨간 헤더 + 본문 | A vs B 직접 비교 |
|
||||
| `banner-gradient.html` | 파란 그라데이션 배너 + 중앙 흰 텍스트 | 섹션 구분, 핵심 선언 |
|
||||
| `dark-bullet-list.html` | 짙은 남색 배경 + 파란 제목 + 흰 불릿 | 핵심 포인트 강조 (무게감) |
|
||||
| `highlight-strip.html` | 가로 색상 구간 + 흰 라벨 | 카테고리 색상 분류 바 |
|
||||
| `callout-solution.html` | 파란 배경+테두리 + 아이콘 + 제목+설명 | 해결책, 솔루션, 방향성 |
|
||||
| `callout-warning.html` | 빨간 배경+테두리 + 아이콘 + 제목+설명 | 문제점, 주의, 잘못된 접근 |
|
||||
| `tab-label-row.html` | 가로 탭 버튼 (선택됨=색상, 나머지=회색) | 카테고리 전환/분류 표시 |
|
||||
| `divider-text.html` | 좌우 회색 선 + 중앙 텍스트 | 가벼운 섹션 구분, 휴식점 |
|
||||
|
||||
---
|
||||
|
||||
## 📁 media/ (5개) — 이미지/미디어
|
||||
|
||||
| 파일 | 설명 | 언제 사용 |
|
||||
|------|------|---------|
|
||||
| `image-row-2col.html` | 이미지 2장 나란히 (354px) | 시공 사진 2장, 현장 비교 |
|
||||
| `image-grid-2x2.html` | 이미지 4장 2x2 격자 (200px) | 현장 사진 4장, 갤러리 |
|
||||
| `image-side-text.html` | 좌:이미지(320px) + 우:제목+설명+불릿 | 이미지 설명, 시스템 소개 |
|
||||
| `image-full-caption.html` | 전체 너비 이미지 1장 + 캡션 | 핵심 도표, 대형 다이어그램 |
|
||||
| `image-before-after.html` | Before(회색) + → + After(파란) | 변화 전후 비교 |
|
||||
|
||||
---
|
||||
|
||||
## 추가 규칙
|
||||
|
||||
1. **이름 규칙:** `{유형}-{특징}.html`
|
||||
2. **모든 변형은 catalog.yaml에 등록** — 미등록 = 팀장이 모름
|
||||
3. **각 파일 상단에 HTML 주석으로 용도/슬롯 명시**
|
||||
4. **디자인 토큰 사용** — 하드코딩 색상 금지 (가능한 범위에서)
|
||||
5. **높이 고정 금지** — 모드 독립적 (슬라이드/웹 겸용)
|
||||
6. **visuals/는 SVG로 제작** — CSS 원/AI 이미지 금지
|
||||
74
templates/blocks/cards/card-compare-3col.html
Normal file
74
templates/blocks/cards/card-compare-3col.html
Normal file
@@ -0,0 +1,74 @@
|
||||
<!-- 3단 비교 카드: 각각 다른 색상 헤더 + 아이콘/이미지 + 불릿 -->
|
||||
<!--
|
||||
📋 card-compare-3col
|
||||
─────────────────
|
||||
용도: 3개 카테고리 비교 (예: 상용SW / 3rd Party / 전문SW)
|
||||
슬롯: cards[] (각 카드에 title, subtitle, color, image, bullets[])
|
||||
Figma 원본: 2-2_03 "상용 / 3rd Party(범용) / 전문·전용 S/W"
|
||||
-->
|
||||
<div class="block-compare-3" style="--cc-count: {{ cards|length }}">
|
||||
{% for card in cards %}
|
||||
<div class="cc-card">
|
||||
<div class="cc-header" style="background: {{ card.color | default('#2563eb') }}">
|
||||
<div class="cc-title">{{ card.title }}</div>
|
||||
{% if card.subtitle %}<div class="cc-sub">{{ card.subtitle }}</div>{% endif %}
|
||||
</div>
|
||||
{% if card.image %}
|
||||
<img class="cc-img" src="{{ card.image }}" alt="{{ card.title }}">
|
||||
{% endif %}
|
||||
{% if card.bullets %}
|
||||
<ul class="cc-list">
|
||||
{% for item in card.bullets %}
|
||||
<li>{{ item }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-compare-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--cc-count, 3), 1fr);
|
||||
gap: 14px;
|
||||
}
|
||||
.cc-card {
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: var(--radius);
|
||||
overflow: hidden;
|
||||
background: #ffffff;
|
||||
}
|
||||
.cc-header {
|
||||
padding: 12px 16px;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
}
|
||||
.cc-title {
|
||||
font-size: 15px;
|
||||
font-weight: 800;
|
||||
}
|
||||
.cc-sub {
|
||||
font-size: 11px;
|
||||
opacity: 0.85;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.cc-img {
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
object-fit: contain;
|
||||
background: #f8fafc;
|
||||
padding: 8px;
|
||||
}
|
||||
.cc-list {
|
||||
list-style: disc;
|
||||
padding: 12px 16px 14px 30px;
|
||||
font-size: 13px;
|
||||
color: #334155;
|
||||
line-height: 1.7;
|
||||
}
|
||||
.cc-list li {
|
||||
margin-bottom: 3px;
|
||||
white-space: pre-line;
|
||||
}
|
||||
</style>
|
||||
77
templates/blocks/cards/card-dark-overlay.html
Normal file
77
templates/blocks/cards/card-dark-overlay.html
Normal file
@@ -0,0 +1,77 @@
|
||||
<!-- 다크 오버레이 카드: 배경 이미지 + 흰 텍스트 오버레이 -->
|
||||
<!--
|
||||
📋 card-dark-overlay
|
||||
─────────────────
|
||||
용도: 키워드+짧은 설명을 시각적으로 강조. 이미지 위에 다크 오버레이 + 흰 텍스트.
|
||||
슬롯: cards[] (각 카드에 image, title, description)
|
||||
Figma 원본: 2-2_01 > 아이콘 카드 5열 (협업지원, 오류감소, 생산성향상 등)
|
||||
-->
|
||||
<div class="block-card-dark" style="--cd-count: {{ cards|length }}">
|
||||
{% for card in cards %}
|
||||
<div class="cd-card">
|
||||
{% if card.image %}
|
||||
<img class="cd-bg" src="{{ card.image }}" alt="">
|
||||
{% else %}
|
||||
<div class="cd-bg cd-bg-default"></div>
|
||||
{% endif %}
|
||||
<div class="cd-overlay">
|
||||
<div class="cd-title">{{ card.title }}</div>
|
||||
{% if card.description %}<div class="cd-desc">{{ card.description }}</div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-card-dark {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--cd-count, 3), 1fr);
|
||||
gap: 12px;
|
||||
}
|
||||
.cd-card {
|
||||
position: relative;
|
||||
border-radius: var(--radius);
|
||||
overflow: hidden;
|
||||
height: 200px;
|
||||
}
|
||||
.cd-bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
z-index: 1;
|
||||
}
|
||||
.cd-bg-default {
|
||||
background: linear-gradient(135deg, #1e3a5f 0%, #2c5282 100%);
|
||||
}
|
||||
.cd-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 2;
|
||||
background: linear-gradient(180deg, rgba(0,0,0,0.15) 0%, rgba(0,0,0,0.55) 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
}
|
||||
.cd-title {
|
||||
font-size: 18px;
|
||||
font-weight: 800;
|
||||
line-height: 1.3;
|
||||
margin-bottom: 6px;
|
||||
text-shadow: 0 1px 4px rgba(0,0,0,0.3);
|
||||
}
|
||||
.cd-desc {
|
||||
white-space: pre-line;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
opacity: 0.9;
|
||||
text-shadow: 0 1px 3px rgba(0,0,0,0.3);
|
||||
white-space: pre-line;
|
||||
}
|
||||
</style>
|
||||
52
templates/blocks/cards/card-icon-desc--compact.html
Normal file
52
templates/blocks/cards/card-icon-desc--compact.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<!-- card-icon-desc variant: compact -->
|
||||
<!--
|
||||
📋 card-icon-desc--compact
|
||||
─────────────────
|
||||
용도: 높이가 부족할 때 아이콘 카드를 축소 렌더링
|
||||
슬롯: cards[] (기존과 동일 — icon, title, description)
|
||||
기존 card-icon-desc의 색상/구조 유지, 패딩/아이콘 축소
|
||||
-->
|
||||
<div class="block-card-icon-compact" style="--ci-count: {{ column_override | default(cards|length) }}">
|
||||
{% for card in cards %}
|
||||
<div class="cid-card-c">
|
||||
{% if card.icon %}<div class="cid-icon-c">{{ card.icon }}</div>{% endif %}
|
||||
<div class="cid-title-c">{{ card.title }}</div>
|
||||
{% if card.description %}<div class="cid-desc-c">{{ card.description }}</div>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-card-icon-compact {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--ci-count, 3), 1fr);
|
||||
gap: 8px;
|
||||
}
|
||||
.cid-card-c {
|
||||
text-align: center;
|
||||
padding: 8px 8px;
|
||||
background: #f8fafc;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
.cid-icon-c {
|
||||
font-size: 1.4rem;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.cid-title-c {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.cid-desc-c {
|
||||
font-size: 10px;
|
||||
color: #475569;
|
||||
line-height: 1.5;
|
||||
white-space: pre-line;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
48
templates/blocks/cards/card-icon-desc.html
Normal file
48
templates/blocks/cards/card-icon-desc.html
Normal file
@@ -0,0 +1,48 @@
|
||||
<!-- 아이콘 설명 카드: 아이콘 + 제목 + 설명 (2~4열) -->
|
||||
<!--
|
||||
📋 card-icon-desc
|
||||
─────────────────
|
||||
용도: 기능/특성/장점을 아이콘과 함께 나열. 시각적으로 분류.
|
||||
슬롯: cards[] (각 카드에 icon, title, description)
|
||||
Figma 원본: 2-3_01 아이콘 3열 설명
|
||||
-->
|
||||
<div class="block-card-icon" style="--ci-count: {{ column_override | default(cards|length) }}">
|
||||
{% for card in cards %}
|
||||
<div class="cid-card">
|
||||
{% if card.icon %}<div class="cid-icon">{{ card.icon }}</div>{% endif %}
|
||||
<div class="cid-title">{{ card.title }}</div>
|
||||
{% if card.description %}<div class="cid-desc">{{ card.description }}</div>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-card-icon {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--ci-count, 3), 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
.cid-card {
|
||||
text-align: center;
|
||||
padding: 20px 16px;
|
||||
background: #f8fafc;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
.cid-icon {
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.cid-title {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.cid-desc {
|
||||
font-size: 13px;
|
||||
color: #475569;
|
||||
line-height: 1.7;
|
||||
white-space: pre-line;
|
||||
}
|
||||
</style>
|
||||
96
templates/blocks/cards/card-image-3col.html
Normal file
96
templates/blocks/cards/card-image-3col.html
Normal file
@@ -0,0 +1,96 @@
|
||||
<!-- 이미지 카드: 상단 이미지 + 하단 텍스트 (2~4열) -->
|
||||
<!--
|
||||
📋 card-image
|
||||
─────────────────
|
||||
용도: 단계별 설명, 카테고리별 설명 (이미지가 핵심인 카드)
|
||||
슬롯: cards[] 배열 (각 카드에 image, title, title_en, items[])
|
||||
Figma 원본: 2-1_02 > Group 1171281594 (카드 3열)
|
||||
-->
|
||||
<div class="block-card-image" style="--ci-count: {{ cards|length }}">
|
||||
{% for card in cards %}
|
||||
<div class="ci-card">
|
||||
{% if card.image %}
|
||||
<img class="ci-img" src="{{ card.image }}" alt="{{ card.title }}">
|
||||
{% endif %}
|
||||
<div class="ci-body">
|
||||
<div class="ci-title" style="color: {{ card.color | default('var(--color-accent, #006aff)') }}">{{ card.title }}</div>
|
||||
{% if card.title_en %}<div class="ci-title-en">{{ card.title_en }}</div>{% endif %}
|
||||
<div class="ci-divider"></div>
|
||||
<ul class="ci-list">
|
||||
{% for item in card.bullets %}
|
||||
<li>{{ item }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% if card.source %}<div class="ci-source">{{ card.source }}</div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-card-image {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--ci-count, 3), 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
.ci-card {
|
||||
background: var(--color-bg, #ffffff);
|
||||
border-radius: var(--radius, 8px);
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.ci-img {
|
||||
width: 100%;
|
||||
height: 160px;
|
||||
object-fit: contain;
|
||||
background: #f8f9fb;
|
||||
padding: 10px;
|
||||
}
|
||||
.ci-body {
|
||||
padding: 16px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.ci-title {
|
||||
font-size: 14px;
|
||||
font-weight: var(--weight-bold, 700);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.ci-title-en {
|
||||
font-size: 12px;
|
||||
font-weight: var(--weight-normal, 400);
|
||||
color: var(--color-text-secondary, #666);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.ci-divider {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background: #000;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.ci-list {
|
||||
white-space: pre-line;
|
||||
list-style: disc;
|
||||
padding-left: 18px;
|
||||
font-size: 13px;
|
||||
line-height: 1.7;
|
||||
color: var(--color-text, #000);
|
||||
flex: 1;
|
||||
}
|
||||
.ci-list li {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.ci-source {
|
||||
font-size: 11px;
|
||||
color: var(--color-text-light, #94a3b8);
|
||||
font-style: italic;
|
||||
margin-top: 8px;
|
||||
border-top: 1px solid var(--color-border, #e2e8f0);
|
||||
padding-top: 6px;
|
||||
}
|
||||
</style>
|
||||
62
templates/blocks/cards/card-image-round.html
Normal file
62
templates/blocks/cards/card-image-round.html
Normal file
@@ -0,0 +1,62 @@
|
||||
<!-- 원형 이미지 카드: 원형 이미지 + 하단 제목/설명 -->
|
||||
<!--
|
||||
📋 card-image-round
|
||||
─────────────────
|
||||
용도: 포트폴리오형, 팀 소개, 가치/비전 표현 (원형 이미지가 핵심)
|
||||
슬롯: cards[] (각 카드에 image, title, description)
|
||||
Figma 원본: 1장_가치 하단 3열 원형 이미지 + 설명
|
||||
-->
|
||||
<div class="block-card-round" style="--cr-count: {{ cards|length }}">
|
||||
{% for card in cards %}
|
||||
<div class="cr-card">
|
||||
{% if card.image %}
|
||||
<div class="cr-img-wrap">
|
||||
<img src="{{ card.image }}" alt="{{ card.title | default('') }}">
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="cr-title">{{ card.title }}</div>
|
||||
{% if card.description %}<div class="cr-desc">{{ card.description }}</div>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-card-round {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--cr-count, 3), 1fr);
|
||||
gap: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
.cr-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.cr-img-wrap {
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
border: 3px solid #e2e8f0;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.cr-img-wrap img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
.cr-title {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.cr-desc {
|
||||
font-size: 13px;
|
||||
color: #475569;
|
||||
line-height: 1.6;
|
||||
white-space: pre-line;
|
||||
max-width: 200px;
|
||||
}
|
||||
</style>
|
||||
60
templates/blocks/cards/card-numbered--horizontal.html
Normal file
60
templates/blocks/cards/card-numbered--horizontal.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<!-- card-numbered variant: horizontal -->
|
||||
<!--
|
||||
📋 card-numbered--horizontal
|
||||
─────────────────
|
||||
용도: 같은 구조의 항목 2-3개를 가로로 나란히 비교
|
||||
슬롯: items[] (기존과 동일 — title, description)
|
||||
기존 card-numbered의 색상/스타일 유지, 배치만 가로
|
||||
-->
|
||||
<div class="block-card-num-h" style="--cn-count: {{ items|length }}">
|
||||
{% for item in items %}
|
||||
<div class="cn-item-h">
|
||||
<div class="cn-number-h" style="background: {{ item.color | default('#2563eb') }}">{{ loop.index }}</div>
|
||||
<div class="cn-body-h">
|
||||
<div class="cn-title-h">{{ item.title }}</div>
|
||||
<div class="cn-desc-h">{{ item.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-card-num-h {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--cn-count, 2), 1fr);
|
||||
gap: 10px;
|
||||
}
|
||||
.cn-item-h {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
padding: 10px 14px;
|
||||
background: #f8fafc;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
.cn-number-h {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #ffffff;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.cn-title-h {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.cn-desc-h {
|
||||
font-size: 11px;
|
||||
color: #475569;
|
||||
line-height: 1.6;
|
||||
white-space: pre-line;
|
||||
}
|
||||
</style>
|
||||
60
templates/blocks/cards/card-numbered.html
Normal file
60
templates/blocks/cards/card-numbered.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<!-- 번호 카드: 순서 번호 + 제목 + 설명 (세로 나열) -->
|
||||
<!--
|
||||
📋 card-numbered
|
||||
─────────────────
|
||||
용도: 순서가 있는 항목 나열 (1. 2. 3.), 실행 조건, 요구사항
|
||||
슬롯: items[] (각 항목에 title, description)
|
||||
card-icon-desc와 다른 점: 아이콘 대신 순서 번호, 세로 나열
|
||||
-->
|
||||
<div class="block-card-num">
|
||||
{% for item in items %}
|
||||
<div class="cn-item">
|
||||
<div class="cn-number" style="background: {{ item.color | default('#2563eb') }}">{{ loop.index }}</div>
|
||||
<div class="cn-body">
|
||||
<div class="cn-title">{{ item.title }}</div>
|
||||
{% if item.description %}<div class="cn-desc">{{ item.description }}</div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-card-num {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
.cn-item {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
align-items: flex-start;
|
||||
padding: 12px 16px;
|
||||
background: #f8fafc;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
.cn-number {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #ffffff;
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.cn-title {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.cn-desc {
|
||||
font-size: 13px;
|
||||
color: #475569;
|
||||
line-height: 1.7;
|
||||
white-space: pre-line;
|
||||
}
|
||||
</style>
|
||||
57
templates/blocks/cards/card-stat-number.html
Normal file
57
templates/blocks/cards/card-stat-number.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<!-- 통계 숫자 카드: 큰 숫자 + 라벨 + 설명 -->
|
||||
<!--
|
||||
📋 card-stat-number
|
||||
─────────────────
|
||||
용도: KPI, 성과 수치, 목표 달성률, 비용 절감율 등 핵심 지표 강조
|
||||
슬롯: stats[] (각 항목에 number, unit, label, description, color)
|
||||
Figma 참고: 건설 정책 수치 (30% 절감, 40% 감소 등)
|
||||
-->
|
||||
<div class="block-stat" style="--st-count: {{ stats|length }}">
|
||||
{% for stat in stats %}
|
||||
<div class="st-card">
|
||||
<div class="st-number" style="color: {{ stat.color | default('#2563eb') }}">
|
||||
{{ stat.number }}<span class="st-unit">{{ stat.unit | default('') }}</span>
|
||||
</div>
|
||||
<div class="st-label">{{ stat.label }}</div>
|
||||
{% if stat.description %}<div class="st-desc">{{ stat.description }}</div>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-stat {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--st-count, 3), 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
.st-card {
|
||||
text-align: center;
|
||||
padding: 20px 12px;
|
||||
background: #f8fafc;
|
||||
border-radius: var(--radius);
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
.st-number {
|
||||
font-size: 36px;
|
||||
font-weight: 900;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.st-unit {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
margin-left: 2px;
|
||||
}
|
||||
.st-label {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-top: 6px;
|
||||
}
|
||||
.st-desc {
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
margin-top: 4px;
|
||||
line-height: 1.5;
|
||||
white-space: pre-line;
|
||||
}
|
||||
</style>
|
||||
93
templates/blocks/cards/card-step-vertical.html
Normal file
93
templates/blocks/cards/card-step-vertical.html
Normal file
@@ -0,0 +1,93 @@
|
||||
<!-- 세로 단계 카드: 좌측 단계 마커 + 우측 이미지/텍스트 -->
|
||||
<!--
|
||||
📋 card-step-vertical
|
||||
─────────────────
|
||||
용도: 생애주기 단계별 설명, 시간순 프로세스 (설계→시공→운영→유지관리)
|
||||
슬롯: steps[] (각 단계에 phase, title, description, image, color)
|
||||
Figma 원본: 2-3_04 "건설 생애주기와 정보모델 연계" (설계단계/시공단계/운영관리/유지관리)
|
||||
-->
|
||||
<div class="block-step-v">
|
||||
{% for step in steps %}
|
||||
<div class="sv-step">
|
||||
<div class="sv-marker" style="background: {{ step.color | default('#2563eb') }}">
|
||||
<div class="sv-phase">{{ step.phase }}</div>
|
||||
</div>
|
||||
<div class="sv-content">
|
||||
<div class="sv-title">{{ step.title }}</div>
|
||||
{% if step.image %}
|
||||
<img class="sv-img" src="{{ step.image }}" alt="{{ step.title }}">
|
||||
{% endif %}
|
||||
{% if step.description %}<div class="sv-desc">{{ step.description }}</div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if not loop.last %}
|
||||
<div class="sv-connector">
|
||||
<div class="sv-line" style="background: {{ step.color | default('#2563eb') }}"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-step-v {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
.sv-step {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.sv-marker {
|
||||
width: 100px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 8px;
|
||||
padding: 10px 12px;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
}
|
||||
.sv-phase {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.sv-content {
|
||||
flex: 1;
|
||||
background: #f8fafc;
|
||||
border-radius: 8px;
|
||||
padding: 14px;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
.sv-title {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.sv-img {
|
||||
width: 100%;
|
||||
max-height: 150px;
|
||||
object-fit: cover;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.sv-desc {
|
||||
font-size: 13px;
|
||||
color: #475569;
|
||||
line-height: 1.7;
|
||||
white-space: pre-line;
|
||||
}
|
||||
.sv-connector {
|
||||
display: flex;
|
||||
justify-content: 50px;
|
||||
padding-left: 48px;
|
||||
height: 20px;
|
||||
}
|
||||
.sv-line {
|
||||
width: 3px;
|
||||
height: 100%;
|
||||
border-radius: 2px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
</style>
|
||||
63
templates/blocks/cards/card-tag-image.html
Normal file
63
templates/blocks/cards/card-tag-image.html
Normal file
@@ -0,0 +1,63 @@
|
||||
<!-- 태그 카드: 상단 태그 라벨 + 이미지 + 설명 -->
|
||||
<!--
|
||||
📋 card-tag-image
|
||||
─────────────────
|
||||
용도: 카테고리별 분류 (제조/건축/토목 등), 태그로 구분되는 항목
|
||||
슬롯: cards[] (각 카드에 tag, tag_color, image, title, description)
|
||||
Figma 원본: 2-3_01 "산업별 특성과 현장의 모습" (제조, 건축, 인프라/토목)
|
||||
-->
|
||||
<div class="block-card-tag" style="--ct-count: {{ column_override | default(cards|length) }}">
|
||||
{% for card in cards %}
|
||||
<div class="ct-card">
|
||||
<div class="ct-tag" style="background: {{ card.tag_color | default('#2563eb') }}">{{ card.tag }}</div>
|
||||
{% if card.image %}
|
||||
<img class="ct-img" src="{{ card.image }}" alt="{{ card.title | default('') }}">
|
||||
{% endif %}
|
||||
{% if card.title %}<div class="ct-title">{{ card.title }}</div>{% endif %}
|
||||
{% if card.description %}<div class="ct-desc">{{ card.description }}</div>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-card-tag {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--ct-count, 3), 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
.ct-card {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.ct-tag {
|
||||
display: inline-block;
|
||||
padding: 4px 14px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
border-radius: 0 0 8px 0;
|
||||
align-self: flex-start;
|
||||
}
|
||||
.ct-img {
|
||||
width: 100%;
|
||||
height: 140px;
|
||||
object-fit: cover;
|
||||
}
|
||||
.ct-title {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
padding: 10px 14px 4px;
|
||||
}
|
||||
.ct-desc {
|
||||
font-size: 13px;
|
||||
color: #475569;
|
||||
line-height: 1.7;
|
||||
padding: 0 14px 14px;
|
||||
white-space: pre-line;
|
||||
}
|
||||
</style>
|
||||
33
templates/blocks/emphasis/banner-gradient.html
Normal file
33
templates/blocks/emphasis/banner-gradient.html
Normal file
@@ -0,0 +1,33 @@
|
||||
<!-- 그라데이션 배너 바: 전체 너비 파란 그라데이션 + 중앙 텍스트 -->
|
||||
<!--
|
||||
📋 banner-gradient
|
||||
─────────────────
|
||||
용도: 섹션 구분, 핵심 선언, 강조 문구를 전체 너비 배너로
|
||||
슬롯: text (필수), sub_text (선택)
|
||||
Figma 원본: 2-2_01 하단, 2-2_03 분류 바
|
||||
-->
|
||||
<div class="block-banner-grad">
|
||||
<div class="bg-text">{{ text }}</div>
|
||||
{% if sub_text %}<div class="bg-sub">{{ sub_text }}</div>{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-banner-grad {
|
||||
background: linear-gradient(135deg, #006aff 0%, #00aaff 100%);
|
||||
border-radius: 8px;
|
||||
padding: 16px 30px;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
}
|
||||
.bg-text {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.bg-sub {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
opacity: 0.85;
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
55
templates/blocks/emphasis/callout-solution.html
Normal file
55
templates/blocks/emphasis/callout-solution.html
Normal file
@@ -0,0 +1,55 @@
|
||||
<!-- 솔루션 콜아웃: 강조 배경 + 아이콘 + 제목 + 설명 -->
|
||||
<!--
|
||||
📋 callout-solution
|
||||
─────────────────
|
||||
용도: 핵심 해결책/솔루션/방향성 강조. 눈에 띄는 콜아웃 박스.
|
||||
슬롯: icon (선택), title (필수), description (필수), source (선택)
|
||||
Figma 원본: 2-3_05 "Solution 제시 포인트"
|
||||
-->
|
||||
<div class="block-callout-sol">
|
||||
{% if icon %}<div class="cs-icon">{{ icon }}</div>{% endif %}
|
||||
<div class="cs-body">
|
||||
<div class="cs-title">{{ title }}</div>
|
||||
<div class="cs-desc">{{ description }}</div>
|
||||
{% if source %}<div class="cs-source">{{ source }}</div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-callout-sol {
|
||||
background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
|
||||
border: 2px solid #93c5fd;
|
||||
border-radius: var(--radius);
|
||||
padding: 20px 24px;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.cs-icon {
|
||||
font-size: 2rem;
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.cs-body {
|
||||
flex: 1;
|
||||
}
|
||||
.cs-title {
|
||||
font-size: 17px;
|
||||
font-weight: 800;
|
||||
color: #1e40af;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.cs-desc {
|
||||
font-size: 14px;
|
||||
color: #334155;
|
||||
line-height: 1.7;
|
||||
white-space: pre-line;
|
||||
word-break: keep-all;
|
||||
}
|
||||
.cs-source {
|
||||
font-size: 11px;
|
||||
color: #64748b;
|
||||
font-style: italic;
|
||||
margin-top: 8px;
|
||||
}
|
||||
</style>
|
||||
45
templates/blocks/emphasis/callout-warning.html
Normal file
45
templates/blocks/emphasis/callout-warning.html
Normal file
@@ -0,0 +1,45 @@
|
||||
<!-- 경고 콜아웃: 주의/경고/문제점 강조 -->
|
||||
<!--
|
||||
📋 callout-warning
|
||||
─────────────────
|
||||
용도: 문제점 지적, 주의사항, 잘못된 접근 경고
|
||||
슬롯: title (필수), description (필수), icon (선택)
|
||||
callout-solution과 다른 점: 경고 톤 (빨간/주황), 문제 지적용
|
||||
-->
|
||||
<div class="block-callout-warn">
|
||||
{% if icon %}<div class="cw-icon">{{ icon }}</div>{% endif %}
|
||||
<div class="cw-body">
|
||||
<div class="cw-title">{{ title }}</div>
|
||||
<div class="cw-desc">{{ description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-callout-warn {
|
||||
background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);
|
||||
border: 2px solid #fca5a5;
|
||||
border-radius: var(--radius);
|
||||
padding: 20px 24px;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.cw-icon {
|
||||
font-size: 2rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.cw-body { flex: 1; }
|
||||
.cw-title {
|
||||
font-size: 17px;
|
||||
font-weight: 800;
|
||||
color: #991b1b;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.cw-desc {
|
||||
font-size: 14px;
|
||||
color: #7f1d1d;
|
||||
line-height: 1.7;
|
||||
white-space: pre-line;
|
||||
word-break: keep-all;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,97 @@
|
||||
<!-- comparison-2col variant: cards-in-container -->
|
||||
<!--
|
||||
📋 comparison-2col--cards-in-container
|
||||
─────────────────
|
||||
용도: 포함 관계 시각화 (A 안에 B, C, D가 포함됨)
|
||||
슬롯: container_label, container_desc, cards[] (각 카드에 letter, label, description)
|
||||
기존 comparison-2col의 색상 계열 활용
|
||||
-->
|
||||
<div class="block-container-cards">
|
||||
<div class="cc-outer">
|
||||
<div class="cc-badge">{{ container_label }}</div>
|
||||
{% if container_desc %}<div class="cc-desc">{{ container_desc }}</div>{% endif %}
|
||||
<div class="cc-grid" style="--cc-count: {{ cards|length }}">
|
||||
{% for card in cards %}
|
||||
<div class="cc-card">
|
||||
{% if card.letter %}
|
||||
<div class="cc-icon">{{ card.letter }}</div>
|
||||
{% endif %}
|
||||
<div class="cc-label">{{ card.label }}</div>
|
||||
{% if card.description %}<div class="cc-text">{{ card.description }}</div>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-container-cards {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
.cc-outer {
|
||||
width: 100%;
|
||||
border: 3px solid #2563eb;
|
||||
border-radius: 14px;
|
||||
padding: 16px 14px 12px;
|
||||
background: linear-gradient(180deg, #eff6ff, #dbeafe);
|
||||
position: relative;
|
||||
}
|
||||
.cc-badge {
|
||||
position: absolute;
|
||||
top: -11px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: #2563eb;
|
||||
color: #ffffff;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
padding: 3px 18px;
|
||||
border-radius: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.cc-desc {
|
||||
text-align: center;
|
||||
font-size: 11px;
|
||||
color: #1e40af;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.cc-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--cc-count, 3), 1fr);
|
||||
gap: 10px;
|
||||
}
|
||||
.cc-card {
|
||||
background: #ffffff;
|
||||
border: 2px solid #93c5fd;
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
.cc-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #93c5fd, #2563eb);
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
font-weight: 900;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto 6px;
|
||||
}
|
||||
.cc-label {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.cc-text {
|
||||
font-size: 10px;
|
||||
color: #64748b;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
52
templates/blocks/emphasis/comparison-2col.html
Normal file
52
templates/blocks/emphasis/comparison-2col.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<!-- 비교 블록: 2단 병렬 레이아웃 -->
|
||||
<div class="block-comparison">
|
||||
<div class="comparison-left">
|
||||
<div class="comparison-header comparison-header--left">{{ left_title }}</div>
|
||||
{% if left_subtitle %}<div class="comparison-subtitle">{{ left_subtitle }}</div>{% endif %}
|
||||
<div class="comparison-content">{{ left_content }}</div>
|
||||
</div>
|
||||
<div class="comparison-divider"></div>
|
||||
<div class="comparison-right">
|
||||
<div class="comparison-header comparison-header--right">{{ right_title }}</div>
|
||||
{% if right_subtitle %}<div class="comparison-subtitle">{{ right_subtitle }}</div>{% endif %}
|
||||
<div class="comparison-content">{{ right_content }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-comparison {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
gap: var(--spacing-inner);
|
||||
height: 100%;
|
||||
}
|
||||
.comparison-divider {
|
||||
width: 1px;
|
||||
background: var(--color-border);
|
||||
}
|
||||
.comparison-header {
|
||||
font-size: var(--font-subtitle);
|
||||
font-weight: var(--weight-bold);
|
||||
padding-bottom: var(--spacing-small);
|
||||
margin-bottom: var(--spacing-small);
|
||||
border-bottom: var(--accent-border) solid;
|
||||
}
|
||||
.comparison-header--left {
|
||||
border-color: var(--color-accent);
|
||||
color: var(--color-accent);
|
||||
}
|
||||
.comparison-header--right {
|
||||
border-color: var(--color-danger);
|
||||
color: var(--color-danger);
|
||||
}
|
||||
.comparison-subtitle {
|
||||
font-size: var(--font-caption);
|
||||
color: var(--color-text-secondary);
|
||||
margin-bottom: var(--spacing-small);
|
||||
}
|
||||
.comparison-content {
|
||||
white-space: pre-line;
|
||||
font-size: var(--font-body);
|
||||
line-height: var(--line-height-ko);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,65 @@
|
||||
<!-- dark-bullet-list variant: before-after -->
|
||||
<!--
|
||||
📋 dark-bullet-list--before-after
|
||||
─────────────────
|
||||
용도: 기존 방식 → 새 방식 전환/변화를 보여줄 때
|
||||
슬롯: title (선택), changes[] (각 항목에 label, before, after)
|
||||
기존 dark-bullet-list의 색상/배경/radius 그대로 사용
|
||||
-->
|
||||
<div class="block-dark-bullets">
|
||||
{% if title %}<div class="db-title">{{ title }}</div>{% endif %}
|
||||
<div class="db-changes">
|
||||
{% for item in changes %}
|
||||
<div class="db-change">
|
||||
<div class="db-change-label">{{ item.label }}</div>
|
||||
<div class="db-change-before">{{ item.before }}</div>
|
||||
<div class="db-change-after">→ {{ item.after }}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* 기존 dark-bullet-list CSS 재사용 */
|
||||
.block-dark-bullets {
|
||||
background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
|
||||
border-radius: 8px;
|
||||
padding: 14px 20px;
|
||||
color: #ffffff;
|
||||
}
|
||||
.db-title {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 8px;
|
||||
color: #93c5fd;
|
||||
}
|
||||
/* variant: before-after 2열 구조 */
|
||||
.db-changes {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 6px;
|
||||
}
|
||||
.db-change {
|
||||
background: rgba(255,255,255,0.06);
|
||||
border-radius: 6px;
|
||||
padding: 8px 10px;
|
||||
border-left: 3px solid #60a5fa;
|
||||
}
|
||||
.db-change-label {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
color: #93c5fd;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.db-change-before {
|
||||
font-size: 10px;
|
||||
color: #94a3b8;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.db-change-after {
|
||||
font-size: 11px;
|
||||
color: #e2e8f0;
|
||||
font-weight: 500;
|
||||
margin-top: 2px;
|
||||
}
|
||||
</style>
|
||||
48
templates/blocks/emphasis/dark-bullet-list.html
Normal file
48
templates/blocks/emphasis/dark-bullet-list.html
Normal file
@@ -0,0 +1,48 @@
|
||||
<!-- 다크 배경 불릿 리스트: 짙은 배경 + 흰 텍스트 불릿 목록 -->
|
||||
<!--
|
||||
📋 dark-bullet-list
|
||||
─────────────────
|
||||
용도: 핵심 포인트를 짙은 배경 위에 강조. 시각적 무게감.
|
||||
슬롯: title (선택), bullets[] (필수)
|
||||
Figma 원본: 2-2_01 하단, 2-3_01 하단 다크 섹션
|
||||
-->
|
||||
<div class="block-dark-bullets">
|
||||
{% if title %}<div class="db-title">{{ title }}</div>{% endif %}
|
||||
<ul class="db-list">
|
||||
{% for item in bullets %}
|
||||
<li>{{ item }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-dark-bullets {
|
||||
background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
|
||||
border-radius: 8px;
|
||||
padding: 20px 28px;
|
||||
color: #ffffff;
|
||||
}
|
||||
.db-title {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 12px;
|
||||
color: #93c5fd;
|
||||
}
|
||||
.db-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
.db-list li {
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
padding-left: 16px;
|
||||
position: relative;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.db-list li::before {
|
||||
content: '•';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: #60a5fa;
|
||||
}
|
||||
</style>
|
||||
32
templates/blocks/emphasis/divider-text.html
Normal file
32
templates/blocks/emphasis/divider-text.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<!-- 텍스트 구분선: 좌우 선 + 중앙 텍스트 -->
|
||||
<!--
|
||||
📋 divider-text
|
||||
─────────────────
|
||||
용도: 섹션 구분, 주제 전환, 시각적 휴식점
|
||||
슬롯: text (필수)
|
||||
-->
|
||||
<div class="block-divider-text">
|
||||
<div class="dt-line"></div>
|
||||
<div class="dt-text">{{ text }}</div>
|
||||
<div class="dt-line"></div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-divider-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 8px 0;
|
||||
}
|
||||
.dt-line {
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: #cbd5e1;
|
||||
}
|
||||
.dt-text {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #64748b;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
31
templates/blocks/emphasis/highlight-strip.html
Normal file
31
templates/blocks/emphasis/highlight-strip.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<!-- 강조 스트립: 3구간 색상 분류 바 -->
|
||||
<!--
|
||||
📋 highlight-strip
|
||||
─────────────────
|
||||
용도: 카테고리별 색상 분류 (예: 상용/범용/전문), 비교 카드 상단 헤더
|
||||
슬롯: segments[] (각 구간에 label, color)
|
||||
Figma 원본: 2-2_03 "상용 | 3rd Party(범용) | 전문·전용 S/W" 색상 바
|
||||
-->
|
||||
<div class="block-strip">
|
||||
{% for seg in segments %}
|
||||
<div class="strip-seg" style="background: {{ seg.color | default('#2563eb') }}; flex: {{ seg.flex | default(1) }}">
|
||||
{{ seg.label }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-strip {
|
||||
display: flex;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.strip-seg {
|
||||
padding: 10px 16px;
|
||||
color: #ffffff;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
59
templates/blocks/emphasis/quote-big-mark.html
Normal file
59
templates/blocks/emphasis/quote-big-mark.html
Normal file
@@ -0,0 +1,59 @@
|
||||
<!-- 큰따옴표 장식 인용: ❝❞ 큰따옴표 + 인용 텍스트 -->
|
||||
<!--
|
||||
📋 quote-big-mark
|
||||
─────────────────
|
||||
용도: 문제 제기, 핵심 발언, 임팩트 있는 인용
|
||||
슬롯: quote_text (필수), source (선택)
|
||||
Figma 원본: DX와 BIM 슬라이드 상단 인용 박스 (큰따옴표 장식)
|
||||
-->
|
||||
<div class="block-quote-big">
|
||||
<div class="qb-mark qb-open">❝</div>
|
||||
<div class="qb-content">
|
||||
<div class="qb-text">{{ quote_text }}</div>
|
||||
{% if source %}<div class="qb-source">— {{ source }}</div>{% endif %}
|
||||
</div>
|
||||
<div class="qb-mark qb-close">❞</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-quote-big {
|
||||
background: #f8fafc;
|
||||
border-radius: var(--radius);
|
||||
padding: 24px 28px;
|
||||
position: relative;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
.qb-mark {
|
||||
font-size: 3rem;
|
||||
color: #cbd5e1;
|
||||
font-weight: 900;
|
||||
line-height: 1;
|
||||
position: absolute;
|
||||
}
|
||||
.qb-open {
|
||||
top: 8px;
|
||||
left: 12px;
|
||||
}
|
||||
.qb-close {
|
||||
bottom: -8px;
|
||||
right: 16px;
|
||||
}
|
||||
.qb-content {
|
||||
padding: 10px 30px 0;
|
||||
}
|
||||
.qb-text {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: #1e293b;
|
||||
line-height: 1.8;
|
||||
word-break: keep-all;
|
||||
white-space: pre-line;
|
||||
}
|
||||
.qb-source {
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
font-style: italic;
|
||||
margin-top: 10px;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
37
templates/blocks/emphasis/quote-question.html
Normal file
37
templates/blocks/emphasis/quote-question.html
Normal file
@@ -0,0 +1,37 @@
|
||||
<!-- 질문형 강조 박스: 큰 질문 텍스트 + 부연 설명 -->
|
||||
<!--
|
||||
📋 quote-question
|
||||
─────────────────
|
||||
용도: 독자에게 질문 던지기, 문제 인식 유도, 전환점 강조
|
||||
슬롯: question (필수), description (선택)
|
||||
Figma 원본: 2-3_05 "지금의 방식으로도 가능할까?"
|
||||
-->
|
||||
<div class="block-quote-q">
|
||||
<div class="qq-question">{{ question }}</div>
|
||||
{% if description %}<div class="qq-desc">{{ description }}</div>{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-quote-q {
|
||||
background: linear-gradient(135deg, #f0f7ff 0%, #e8f1fb 100%);
|
||||
border: 2px solid #b8d4f0;
|
||||
border-radius: var(--radius);
|
||||
padding: 28px 36px;
|
||||
text-align: center;
|
||||
}
|
||||
.qq-question {
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
color: #1e3a5f;
|
||||
line-height: 1.5;
|
||||
word-break: keep-all;
|
||||
}
|
||||
.qq-desc {
|
||||
white-space: pre-line;
|
||||
font-size: 14px;
|
||||
color: #4a6b8a;
|
||||
margin-top: 10px;
|
||||
line-height: 1.7;
|
||||
word-break: keep-all;
|
||||
}
|
||||
</style>
|
||||
39
templates/blocks/emphasis/tab-label-row.html
Normal file
39
templates/blocks/emphasis/tab-label-row.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<!-- 탭 라벨 행: 가로로 나열된 탭 버튼 형태 -->
|
||||
<!--
|
||||
📋 tab-label-row
|
||||
─────────────────
|
||||
용도: 카테고리 전환, 분류 표시, 선택된 항목 강조
|
||||
슬롯: tabs[] (각 탭에 label, active, color)
|
||||
Figma 원본: 2-3_02 상단 "건축과 인프라의 건설프로세스 특성" 탭, 2-2_01 탭
|
||||
-->
|
||||
<div class="block-tab-row">
|
||||
{% for tab in tabs %}
|
||||
<div class="tr-tab {% if tab.active %}tr-active{% endif %}" style="{% if tab.active %}background: {{ tab.color | default('#2563eb') }}{% endif %}">
|
||||
{{ tab.label }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-tab-row {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
background: #f1f5f9;
|
||||
border-radius: 8px;
|
||||
padding: 4px;
|
||||
}
|
||||
.tr-tab {
|
||||
flex: 1;
|
||||
padding: 10px 16px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #64748b;
|
||||
border-radius: 6px;
|
||||
cursor: default;
|
||||
}
|
||||
.tr-active {
|
||||
color: #ffffff;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
32
templates/blocks/headers/section-header-bar.html
Normal file
32
templates/blocks/headers/section-header-bar.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<!-- 섹션 헤더 바: 파란 배경 + 흰 텍스트 제목 -->
|
||||
<!--
|
||||
📋 section-header-bar
|
||||
─────────────────
|
||||
용도: 섹션 시작부 강조 헤더. 전체 너비 파란 바 + 흰 대제목.
|
||||
슬롯: title (필수), subtitle (선택)
|
||||
Figma 원본: 2-2_01 "Eng. S/W의 구성", "Eng. S/W의 특성"
|
||||
-->
|
||||
<div class="block-section-bar">
|
||||
<div class="sb-title">{{ title }}</div>
|
||||
{% if subtitle %}<div class="sb-sub">{{ subtitle }}</div>{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-section-bar {
|
||||
background: linear-gradient(135deg, #0d47a1 0%, #1565c0 100%);
|
||||
border-radius: 6px;
|
||||
padding: 14px 24px;
|
||||
text-align: center;
|
||||
}
|
||||
.sb-title {
|
||||
font-size: 18px;
|
||||
font-weight: 800;
|
||||
color: #ffffff;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.sb-sub {
|
||||
font-size: 12px;
|
||||
color: rgba(255,255,255,0.8);
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
69
templates/blocks/headers/section-title-with-bg.html
Normal file
69
templates/blocks/headers/section-title-with-bg.html
Normal file
@@ -0,0 +1,69 @@
|
||||
<!-- 섹션 타이틀: 배경 헤더 위 영문+한글 타이틀 오버레이 -->
|
||||
<!--
|
||||
📋 section-title
|
||||
─────────────────
|
||||
용도: 자세히보기 페이지 상단, 배경 이미지 위에 타이틀 표시
|
||||
슬롯: title_ko (필수), title_en (선택), breadcrumb (선택), bg_image (선택)
|
||||
Figma 원본: 공통 > section_title + bg 컴포넌트
|
||||
-->
|
||||
<div class="block-section-title">
|
||||
{% if bg_image %}
|
||||
<img class="st-bg" src="{{ bg_image }}" alt="">
|
||||
{% else %}
|
||||
<div class="st-bg st-bg-default"></div>
|
||||
{% endif %}
|
||||
{% if breadcrumb %}
|
||||
<div class="st-breadcrumb">{{ breadcrumb }}</div>
|
||||
{% endif %}
|
||||
<div class="st-text">
|
||||
{% if title_en %}<div class="st-en">{{ title_en }}</div>{% endif %}
|
||||
<div class="st-ko">{{ title_ko }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-section-title {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.st-bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
z-index: 1;
|
||||
}
|
||||
.st-bg-default {
|
||||
background: linear-gradient(135deg, #1e3a5f 0%, #2563eb 50%, #4dc4ff 100%);
|
||||
}
|
||||
.st-breadcrumb {
|
||||
position: absolute;
|
||||
top: 18px;
|
||||
left: 89px;
|
||||
z-index: 5;
|
||||
font-size: 13px;
|
||||
color: rgba(255,255,255,0.7);
|
||||
}
|
||||
.st-text {
|
||||
position: absolute;
|
||||
bottom: 40px;
|
||||
left: 89px;
|
||||
z-index: 5;
|
||||
}
|
||||
.st-en {
|
||||
font-size: 15px;
|
||||
font-weight: var(--weight-normal, 400);
|
||||
color: #ffffff;
|
||||
opacity: 0.85;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.st-ko {
|
||||
font-size: 35px;
|
||||
font-weight: var(--weight-bold, 700);
|
||||
color: #ffffff;
|
||||
line-height: 1.3;
|
||||
}
|
||||
</style>
|
||||
41
templates/blocks/headers/topic-center.html
Normal file
41
templates/blocks/headers/topic-center.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<!-- 중앙 정렬 꼭지 헤더: 대제목 + 하단 설명 -->
|
||||
<!--
|
||||
📋 topic-center
|
||||
─────────────────
|
||||
용도: 단독 강조 꼭지, 페이지 중심 주제 선언
|
||||
슬롯: title (필수), subtitle (선택), description (선택)
|
||||
Figma 원본: 2-2_02 "디지털전환을 위한 S/W 필요성"
|
||||
-->
|
||||
<div class="block-topic-center">
|
||||
<div class="tc-title">{{ title }}</div>
|
||||
{% if subtitle %}<div class="tc-sub">{{ subtitle }}</div>{% endif %}
|
||||
{% if description %}<div class="tc-desc">{{ description }}</div>{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-topic-center {
|
||||
text-align: center;
|
||||
padding: 20px 40px;
|
||||
}
|
||||
.tc-title {
|
||||
font-size: 26px;
|
||||
font-weight: 900;
|
||||
color: #1e293b;
|
||||
line-height: 1.4;
|
||||
word-break: keep-all;
|
||||
}
|
||||
.tc-sub {
|
||||
font-size: 14px;
|
||||
color: #2563eb;
|
||||
font-weight: 600;
|
||||
margin-top: 6px;
|
||||
}
|
||||
.tc-desc {
|
||||
font-size: 15px;
|
||||
color: #475569;
|
||||
line-height: 1.7;
|
||||
margin-top: 12px;
|
||||
word-break: keep-all;
|
||||
white-space: pre-line;
|
||||
}
|
||||
</style>
|
||||
39
templates/blocks/headers/topic-left-right.html
Normal file
39
templates/blocks/headers/topic-left-right.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<!-- 꼭지 제목+설명: 좌측 질문/소제목 + 우측 설명 -->
|
||||
<!--
|
||||
📋 topic-header
|
||||
─────────────────
|
||||
용도: 각 꼭지의 시작부, 좌측에 파란 굵은 제목 + 우측에 본문 설명
|
||||
슬롯: title (필수), description (필수)
|
||||
비율: 좌 240px : 우 나머지
|
||||
Figma 원본: sub_제목,내용 (742x68~78)
|
||||
-->
|
||||
<div class="block-topic-header">
|
||||
<div class="th-title">{{ title }}</div>
|
||||
<div class="th-desc">{{ description }}</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-topic-header {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
padding: 12px 0;
|
||||
}
|
||||
.th-title {
|
||||
width: 240px;
|
||||
flex-shrink: 0;
|
||||
font-size: 24px;
|
||||
font-weight: var(--weight-bold, 700);
|
||||
color: var(--color-accent-deep, #004cbe);
|
||||
line-height: 1.4;
|
||||
word-break: keep-all;
|
||||
}
|
||||
.th-desc {
|
||||
white-space: pre-line;
|
||||
flex: 1;
|
||||
font-size: 16px;
|
||||
font-weight: var(--weight-normal, 400);
|
||||
color: var(--color-text, #000000);
|
||||
line-height: 1.7;
|
||||
word-break: keep-all;
|
||||
}
|
||||
</style>
|
||||
57
templates/blocks/headers/topic-numbered.html
Normal file
57
templates/blocks/headers/topic-numbered.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<!-- 번호 꼭지 헤더: 번호 원형 + 제목 + 구분선 + 설명 -->
|
||||
<!--
|
||||
📋 topic-numbered
|
||||
─────────────────
|
||||
용도: 순서가 있는 꼭지 시작, 단계별 섹션 헤더
|
||||
슬롯: number, title, description (선택), color (선택)
|
||||
topic-left-right와 다른 점: 좌우 배치가 아닌 번호+세로 배치
|
||||
-->
|
||||
<div class="block-topic-num">
|
||||
<div class="tn-header">
|
||||
<div class="tn-number" style="background: {{ color | default('#2563eb') }}">{{ number }}</div>
|
||||
<div class="tn-title">{{ title }}</div>
|
||||
</div>
|
||||
<div class="tn-divider" style="background: {{ color | default('#2563eb') }}"></div>
|
||||
{% if description %}<div class="tn-desc">{{ description }}</div>{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-topic-num {
|
||||
padding: 8px 0;
|
||||
}
|
||||
.tn-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.tn-number {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
font-weight: 800;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.tn-title {
|
||||
font-size: 20px;
|
||||
font-weight: 800;
|
||||
color: #1e293b;
|
||||
}
|
||||
.tn-divider {
|
||||
height: 2px;
|
||||
margin: 8px 0 10px;
|
||||
border-radius: 1px;
|
||||
opacity: 0.3;
|
||||
}
|
||||
.tn-desc {
|
||||
font-size: 15px;
|
||||
color: #475569;
|
||||
line-height: 1.7;
|
||||
white-space: pre-line;
|
||||
word-break: keep-all;
|
||||
}
|
||||
</style>
|
||||
60
templates/blocks/media/image-before-after.html
Normal file
60
templates/blocks/media/image-before-after.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<!-- Before/After 이미지: 좌측 Before + 우측 After + 화살표 -->
|
||||
<!--
|
||||
📋 image-before-after
|
||||
─────────────────
|
||||
용도: 변화 전후 비교, 공정 전후, 디지털 전환 전후
|
||||
슬롯: before_src, before_label, after_src, after_label, caption (선택)
|
||||
-->
|
||||
<div class="block-ba">
|
||||
<div class="ba-item">
|
||||
<div class="ba-label ba-before">{{ before_label | default('Before') }}</div>
|
||||
<img src="{{ before_src }}" alt="before">
|
||||
</div>
|
||||
<div class="ba-arrow">→</div>
|
||||
<div class="ba-item">
|
||||
<div class="ba-label ba-after">{{ after_label | default('After') }}</div>
|
||||
<img src="{{ after_src }}" alt="after">
|
||||
</div>
|
||||
</div>
|
||||
{% if caption %}<div class="ba-caption">{{ caption }}</div>{% endif %}
|
||||
|
||||
<style>
|
||||
.block-ba {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
.ba-item {
|
||||
flex: 1;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
.ba-label {
|
||||
padding: 6px 14px;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
}
|
||||
.ba-before { background: #6b7280; }
|
||||
.ba-after { background: #2563eb; }
|
||||
.ba-item img {
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
.ba-arrow {
|
||||
font-size: 2rem;
|
||||
color: #2563eb;
|
||||
font-weight: 900;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ba-caption {
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
text-align: center;
|
||||
margin-top: 8px;
|
||||
}
|
||||
</style>
|
||||
32
templates/blocks/media/image-full-caption.html
Normal file
32
templates/blocks/media/image-full-caption.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<!-- 전체 너비 이미지 + 캡션 -->
|
||||
<!--
|
||||
📋 image-full-caption
|
||||
─────────────────
|
||||
용도: 핵심 도표, 대형 다이어그램, 전경 사진을 전체 너비로 표시
|
||||
슬롯: src (필수), alt (선택), caption (선택)
|
||||
Figma 원본: 2-3_05 하단 전경 사진, 2-3_03 하단 항공 사진
|
||||
-->
|
||||
<div class="block-img-full">
|
||||
<img src="{{ src }}" alt="{{ alt | default('') }}">
|
||||
{% if caption %}<div class="if-caption">{{ caption }}</div>{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-img-full {
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.block-img-full img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
.if-caption {
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
text-align: center;
|
||||
padding: 6px;
|
||||
background: #f8fafc;
|
||||
}
|
||||
</style>
|
||||
42
templates/blocks/media/image-grid-2x2.html
Normal file
42
templates/blocks/media/image-grid-2x2.html
Normal file
@@ -0,0 +1,42 @@
|
||||
<!-- 이미지 2x2 그리드: 4장 이미지 격자 배치 -->
|
||||
<!--
|
||||
📋 image-grid-2x2
|
||||
─────────────────
|
||||
용도: 현장 사진 4장, 참고 이미지 4장, 사례 이미지 갤러리
|
||||
슬롯: images[] (4개, 각각 src, alt, caption)
|
||||
Figma 원본: 2-1_03 GIS 항공/위성/현장 사진
|
||||
-->
|
||||
<div class="block-img-2x2">
|
||||
{% for img in images %}
|
||||
<div class="ig-item">
|
||||
<img src="{{ img.src }}" alt="{{ img.alt | default('') }}">
|
||||
{% if img.caption %}<div class="ig-caption">{{ img.caption }}</div>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-img-2x2 {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 8px;
|
||||
}
|
||||
.ig-item {
|
||||
overflow: hidden;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.ig-item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
background: var(--color-bg-subtle, #f8fafc);
|
||||
}
|
||||
.ig-caption {
|
||||
font-size: 11px;
|
||||
color: #64748b;
|
||||
text-align: center;
|
||||
padding: 4px;
|
||||
background: #f8f9fb;
|
||||
}
|
||||
</style>
|
||||
40
templates/blocks/media/image-row-2col.html
Normal file
40
templates/blocks/media/image-row-2col.html
Normal file
@@ -0,0 +1,40 @@
|
||||
<!-- 이미지 행: 2~4장 이미지 나란히 -->
|
||||
<!--
|
||||
📋 image-row
|
||||
─────────────────
|
||||
용도: 시공 사진, 근거 자료, 현장 이미지 나란히 배치
|
||||
슬롯: images[] 배열 (각 이미지에 src, alt, caption)
|
||||
Figma 원본: 2-1_02 > image grid (460x354 x 2)
|
||||
-->
|
||||
<div class="block-image-row" style="--ir-count: {{ images|length }}">
|
||||
{% for img in images %}
|
||||
<div class="ir-item">
|
||||
<img src="{{ img.src }}" alt="{{ img.alt | default('') }}">
|
||||
{% if img.caption %}<div class="ir-caption">{{ img.caption }}</div>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-image-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--ir-count, 2), 1fr);
|
||||
gap: 0;
|
||||
}
|
||||
.ir-item {
|
||||
overflow: hidden;
|
||||
}
|
||||
.ir-item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
background: var(--color-bg-subtle, #f8fafc);
|
||||
}
|
||||
.ir-caption {
|
||||
font-size: 11px;
|
||||
color: var(--color-text-light, #94a3b8);
|
||||
text-align: center;
|
||||
padding: 4px;
|
||||
}
|
||||
</style>
|
||||
71
templates/blocks/media/image-side-text.html
Normal file
71
templates/blocks/media/image-side-text.html
Normal file
@@ -0,0 +1,71 @@
|
||||
<!-- 이미지+텍스트 가로 배치: 좌측 이미지 + 우측 텍스트 -->
|
||||
<!--
|
||||
📋 image-side-text
|
||||
─────────────────
|
||||
용도: 이미지에 대한 설명, 제품/시스템 소개, 참고 자료 설명
|
||||
슬롯: image_src, image_alt, title, description, bullets[]
|
||||
Figma 원본: 2-2_01 하단 이미지+텍스트 영역
|
||||
-->
|
||||
<div class="block-img-side">
|
||||
<div class="is-image">
|
||||
<img src="{{ image_src }}" alt="{{ image_alt | default('') }}">
|
||||
</div>
|
||||
<div class="is-text">
|
||||
{% if title %}<div class="is-title">{{ title }}</div>{% endif %}
|
||||
{% if description %}<div class="is-desc">{{ description }}</div>{% endif %}
|
||||
{% if bullets %}
|
||||
<ul class="is-bullets">
|
||||
{% for item in bullets %}
|
||||
<li>{{ item }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-img-side {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.is-image {
|
||||
flex-shrink: 0;
|
||||
width: 320px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.is-image img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
.is-text {
|
||||
flex: 1;
|
||||
padding-top: 4px;
|
||||
}
|
||||
.is-title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-bottom: 8px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.is-desc {
|
||||
font-size: 14px;
|
||||
color: #444;
|
||||
line-height: 1.7;
|
||||
word-break: keep-all;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.is-bullets {
|
||||
list-style: disc;
|
||||
padding-left: 18px;
|
||||
font-size: 13px;
|
||||
color: #333;
|
||||
line-height: 1.7;
|
||||
}
|
||||
.is-bullets li {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
</style>
|
||||
71
templates/blocks/tables/compare-2col-split.html
Normal file
71
templates/blocks/tables/compare-2col-split.html
Normal file
@@ -0,0 +1,71 @@
|
||||
<!-- 2단 분할 비교: 좌측 GIS / 우측 BIM 같은 상세 비교 -->
|
||||
<!--
|
||||
📋 compare-2col-split
|
||||
─────────────────
|
||||
용도: 두 개념/기술의 상세 항목별 비교 (좌우 나란히, 중앙 기준 라벨)
|
||||
슬롯: left_title, right_title, rows[] (각 행에 criteria, left, right)
|
||||
Figma 원본: 2-3_03 GIS vs BIM 비교 (개념/분석/도면/발전 등)
|
||||
-->
|
||||
<div class="block-split-compare">
|
||||
<div class="sc-header">
|
||||
<div class="sc-h-left">{{ left_title }}</div>
|
||||
<div class="sc-h-center">구분</div>
|
||||
<div class="sc-h-right">{{ right_title }}</div>
|
||||
</div>
|
||||
{% for row in rows %}
|
||||
<div class="sc-row {% if loop.index is odd %}sc-row-odd{% endif %}">
|
||||
<div class="sc-left">{{ row.left }}</div>
|
||||
<div class="sc-center">{{ row.criteria }}</div>
|
||||
<div class="sc-right">{{ row.right }}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-split-compare {
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.sc-header {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 100px 1fr;
|
||||
background: linear-gradient(135deg, #0d47a1, #1565c0);
|
||||
color: #ffffff;
|
||||
font-weight: 700;
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
.sc-h-left, .sc-h-right, .sc-h-center {
|
||||
padding: 12px;
|
||||
}
|
||||
.sc-h-center {
|
||||
background: rgba(0,0,0,0.15);
|
||||
font-size: 13px;
|
||||
}
|
||||
.sc-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 100px 1fr;
|
||||
border-top: 1px solid #e2e8f0;
|
||||
}
|
||||
.sc-row-odd {
|
||||
background: #f8fafc;
|
||||
}
|
||||
.sc-left, .sc-right {
|
||||
padding: 10px 14px;
|
||||
font-size: 13px;
|
||||
line-height: 1.7;
|
||||
color: #334155;
|
||||
white-space: pre-line;
|
||||
}
|
||||
.sc-center {
|
||||
padding: 10px 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #1565c0;
|
||||
text-align: center;
|
||||
background: #f0f7ff;
|
||||
border-left: 1px solid #e2e8f0;
|
||||
border-right: 1px solid #e2e8f0;
|
||||
}
|
||||
</style>
|
||||
110
templates/blocks/tables/compare-3col-badge.html
Normal file
110
templates/blocks/tables/compare-3col-badge.html
Normal file
@@ -0,0 +1,110 @@
|
||||
<!-- 비교 테이블: BIM vs DX 스타일 3단 테이블 -->
|
||||
<!--
|
||||
📋 comparison-table
|
||||
─────────────────
|
||||
용도: 다항목 비교 (좌측 A | 중앙 기준 | 우측 B)
|
||||
슬롯: headers[] (3개), rows[][] (각 행 3칸)
|
||||
Figma 원본: 2-1_02 > BIM VS D/X 테이블
|
||||
특징: 중앙 칼럼에 파란 그라데이션 배지, 좌우 불릿 대비
|
||||
-->
|
||||
<div class="block-table-figma">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
{% for header in headers %}
|
||||
<th class="{% if loop.index == 1 %}th-left{% elif loop.index == 2 %}th-center{% else %}th-right{% endif %}">
|
||||
{% if loop.index == 2 %}<span class="th-badge">{{ header }}</span>{% else %}{{ header }}{% endif %}
|
||||
</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in rows %}
|
||||
<tr>
|
||||
{% for cell in row %}
|
||||
<td class="{% if loop.index == 1 %}td-left{% elif loop.index == 2 %}td-center{% else %}td-right{% endif %}">{{ cell }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-table-figma {
|
||||
overflow: auto;
|
||||
container-type: inline-size;
|
||||
}
|
||||
.block-table-figma table {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
border-collapse: collapse;
|
||||
font-size: 13px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
/* 헤더 */
|
||||
.block-table-figma thead th {
|
||||
padding: 14px 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
border-bottom: 2px solid #e8edf2;
|
||||
}
|
||||
.th-left {
|
||||
text-align: center;
|
||||
color: #6bcdff;
|
||||
}
|
||||
.th-center {
|
||||
text-align: center;
|
||||
width: 120px;
|
||||
}
|
||||
.th-badge {
|
||||
display: inline-block;
|
||||
background: linear-gradient(135deg, #006eff 0%, #00aaff 100%);
|
||||
color: #ffffff;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
padding: 8px 28px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.th-right {
|
||||
text-align: center;
|
||||
color: #006eff;
|
||||
}
|
||||
|
||||
/* 본문 */
|
||||
.block-table-figma tbody td {
|
||||
padding: 10px 14px;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.td-left {
|
||||
white-space: pre-line;
|
||||
text-align: center;
|
||||
color: #444;
|
||||
}
|
||||
.td-center {
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
background: #f6f8fb;
|
||||
font-size: 13px;
|
||||
}
|
||||
.td-right {
|
||||
white-space: pre-line;
|
||||
text-align: center;
|
||||
color: #444;
|
||||
}
|
||||
/* container query: 좁은 영역(sidebar 등)에서 폰트 자동 축소 */
|
||||
@container (max-width: 40rem) {
|
||||
.block-table-figma table { font-size: var(--font-caption, 0.8rem); }
|
||||
.block-table-figma thead th { font-size: 14px; padding: 10px 8px; }
|
||||
.block-table-figma tbody td { padding: 8px 10px; }
|
||||
}
|
||||
@container (max-width: 25rem) {
|
||||
.block-table-figma table { font-size: var(--font-small, 0.7rem); }
|
||||
.block-table-figma thead th { font-size: 12px; padding: 8px 6px; }
|
||||
.block-table-figma tbody td { padding: 6px 8px; }
|
||||
.th-badge { padding: 4px 14px; font-size: 12px; }
|
||||
}
|
||||
</style>
|
||||
58
templates/blocks/tables/table-simple-striped.html
Normal file
58
templates/blocks/tables/table-simple-striped.html
Normal file
@@ -0,0 +1,58 @@
|
||||
<!-- 심플 줄무늬 테이블: 범용 데이터 테이블 -->
|
||||
<!--
|
||||
📋 table-simple-striped
|
||||
─────────────────
|
||||
용도: 스펙, 수치, 일정, 항목별 데이터 나열
|
||||
슬롯: headers[], rows[][]
|
||||
compare-3col-badge와 다른 점: VS 배지 없음, 범용 데이터용
|
||||
-->
|
||||
<div class="block-table-striped">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
{% for h in headers %}
|
||||
<th>{{ h }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in rows %}
|
||||
<tr>
|
||||
{% for cell in row %}
|
||||
<td>{{ cell }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-table-striped table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 13px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
.block-table-striped thead th {
|
||||
background: #1e293b;
|
||||
color: #ffffff;
|
||||
font-weight: 700;
|
||||
padding: 10px 14px;
|
||||
text-align: left;
|
||||
font-size: 13px;
|
||||
}
|
||||
.block-table-striped tbody td {
|
||||
padding: 9px 14px;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
white-space: pre-line;
|
||||
color: #334155;
|
||||
}
|
||||
.block-table-striped tbody tr:nth-child(even) {
|
||||
background: #f8fafc;
|
||||
}
|
||||
.block-table-striped tbody td:first-child {
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
}
|
||||
</style>
|
||||
58
templates/blocks/visuals/circle-gradient.html
Normal file
58
templates/blocks/visuals/circle-gradient.html
Normal file
@@ -0,0 +1,58 @@
|
||||
<!-- 원형 라벨: CSS 그라데이션 원 + 중앙 텍스트 -->
|
||||
<!--
|
||||
📋 circle-label
|
||||
─────────────────
|
||||
용도: 섹션 전환점, 핵심 키워드 강조, 시각적 구분자
|
||||
슬롯: label (필수), sub_label (선택)
|
||||
Figma 원본: 2-1_02 > Group 1171281590 (190x190)
|
||||
-->
|
||||
<div class="block-circle-label">
|
||||
<div class="cl-outer">
|
||||
<div class="cl-inner">
|
||||
<div class="cl-text">{{ label }}</div>
|
||||
{% if sub_label %}<div class="cl-sub">{{ sub_label }}</div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-circle-label {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 8px 0;
|
||||
min-height: 0;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
.cl-outer {
|
||||
width: 190px;
|
||||
height: 190px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(180deg, #3db8ff 0%, #006aff 100%);
|
||||
box-shadow: 0 0 30px rgba(0, 106, 255, 0.25);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.cl-inner {
|
||||
width: 170px;
|
||||
height: 170px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(180deg, #4dc4ff 0%, #0080ff 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
}
|
||||
.cl-text {
|
||||
font-size: 20px;
|
||||
font-weight: var(--weight-bold, 700);
|
||||
line-height: 1.4;
|
||||
}
|
||||
.cl-sub {
|
||||
font-size: 12px;
|
||||
opacity: 0.8;
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
74
templates/blocks/visuals/compare-pill-pair.html
Normal file
74
templates/blocks/visuals/compare-pill-pair.html
Normal file
@@ -0,0 +1,74 @@
|
||||
<!-- 비교 박스: 이중 테두리 둥근 박스 2개 + VS -->
|
||||
<!--
|
||||
📋 compare-pill-pair
|
||||
─────────────────
|
||||
용도: 2개 개념 시각적 대비 (비교 테이블 위 헤더)
|
||||
슬롯: left_label, left_sub, right_label, right_sub
|
||||
Figma 원본: 이중 테두리 (바깥 얇은 선 + 안쪽 둥근 박스)
|
||||
-->
|
||||
<div class="block-compare-pill">
|
||||
<div class="cp-item">
|
||||
<div class="cp-outer">
|
||||
<div class="cp-inner">
|
||||
<div class="cp-label">{{ left_label }}</div>
|
||||
{% if left_sub %}<div class="cp-sub">{{ left_sub }}</div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cp-vs">VS</div>
|
||||
<div class="cp-item">
|
||||
<div class="cp-outer">
|
||||
<div class="cp-inner">
|
||||
<div class="cp-label">{{ right_label }}</div>
|
||||
{% if right_sub %}<div class="cp-sub">{{ right_sub }}</div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-compare-pill {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
.cp-item {
|
||||
width: 350px;
|
||||
}
|
||||
.cp-outer {
|
||||
border: 2px solid #a8d8f0;
|
||||
border-radius: 60px;
|
||||
padding: 6px;
|
||||
background: transparent;
|
||||
}
|
||||
.cp-inner {
|
||||
border: 2px solid #7ec8f0;
|
||||
border-radius: 55px;
|
||||
background: linear-gradient(135deg, #e8f4fd 0%, #d6edfa 100%);
|
||||
padding: 18px 30px;
|
||||
text-align: center;
|
||||
}
|
||||
.cp-label {
|
||||
font-size: 18px;
|
||||
font-weight: 800;
|
||||
color: #0088cc;
|
||||
line-height: 1.4;
|
||||
white-space: pre-line;
|
||||
}
|
||||
.cp-sub {
|
||||
font-size: 12px;
|
||||
color: #0088cc;
|
||||
margin-top: 4px;
|
||||
line-height: 1.5;
|
||||
white-space: pre-line;
|
||||
font-weight: 500;
|
||||
}
|
||||
.cp-vs {
|
||||
font-size: 24px;
|
||||
font-weight: 800;
|
||||
color: #333;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
34
templates/blocks/visuals/flow-arrow-horizontal.html
Normal file
34
templates/blocks/visuals/flow-arrow-horizontal.html
Normal file
@@ -0,0 +1,34 @@
|
||||
<!-- 가로 흐름도: 좌→우 화살표로 연결된 단계 (SVG) -->
|
||||
<!--
|
||||
📋 flow-arrow-horizontal
|
||||
─────────────────
|
||||
용도: 발전 과정, 기술 진화, 전환 흐름 (A → B → C)
|
||||
슬롯: steps[] (각 단계에 label, sub)
|
||||
Figma 원본: 2-3_03 "GIS ↔ SPCC → 토공 → ..." / 2-2_04 개발 패러다임
|
||||
-->
|
||||
<div class="block-flow-h">
|
||||
<svg viewBox="0 0 {{ steps|length * 180 }} 80" width="100%" xmlns="http://www.w3.org/2000/svg" font-family="Pretendard Variable, sans-serif">
|
||||
{% for step in steps %}
|
||||
{% set x = loop.index0 * 180 + 70 %}
|
||||
<rect x="{{ x - 60 }}" y="10" width="120" height="50" rx="25" fill="{{ step.color | default('#2563eb') }}" opacity="0.9" />
|
||||
<text x="{{ x }}" y="32" text-anchor="middle" fill="white" font-size="13" font-weight="700">{{ step.label }}</text>
|
||||
{% if step.sub %}
|
||||
<text x="{{ x }}" y="48" text-anchor="middle" fill="white" font-size="10" opacity="0.8">{{ step.sub }}</text>
|
||||
{% endif %}
|
||||
{% if not loop.last %}
|
||||
<polygon points="{{ x + 65 }},35 {{ x + 80 }},35 {{ x + 75 }},28" fill="#94a3b8" />
|
||||
<polygon points="{{ x + 65 }},35 {{ x + 80 }},35 {{ x + 75 }},42" fill="#94a3b8" />
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-flow-h {
|
||||
padding: 10px 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.block-flow-h svg {
|
||||
min-width: 400px;
|
||||
}
|
||||
</style>
|
||||
56
templates/blocks/visuals/keyword-circle-row.html
Normal file
56
templates/blocks/visuals/keyword-circle-row.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<!-- 키워드 원형 행: 원 안에 키워드 + 하단 설명 (SVG) -->
|
||||
<!--
|
||||
📋 keyword-circle-row
|
||||
─────────────────
|
||||
용도: 핵심 키워드를 원형으로 나열하며 각각 설명. 약어 풀이.
|
||||
슬롯: keywords[] (각 항목에 letter, label, description, color)
|
||||
Figma 원본: 2-3_03 G-S-I-M 약어 설명, 2-2_04 개발 조건 키워드
|
||||
-->
|
||||
<div class="block-kw-circles">
|
||||
{% for kw in keywords %}
|
||||
<div class="kw-item">
|
||||
<svg viewBox="0 0 80 80" width="70" height="70" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<radialGradient id="kwGrad{{ loop.index }}" cx="40%" cy="35%" r="60%">
|
||||
<stop offset="0%" stop-color="{{ kw.color_light | default('#93c5fd') }}" />
|
||||
<stop offset="100%" stop-color="{{ kw.color | default('#2563eb') }}" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<circle cx="40" cy="40" r="38" fill="url(#kwGrad{{ loop.index }})" />
|
||||
<text x="40" y="44" text-anchor="middle" dominant-baseline="central" fill="white" font-size="28" font-weight="900" font-family="Pretendard Variable, sans-serif">{{ kw.letter }}</text>
|
||||
</svg>
|
||||
<div class="kw-label">{{ kw.label }}</div>
|
||||
{% if kw.description %}<div class="kw-desc">{{ kw.description }}</div>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-kw-circles {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
padding: 10px 0;
|
||||
}
|
||||
.kw-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
width: 140px;
|
||||
}
|
||||
.kw-label {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.kw-desc {
|
||||
font-size: 12px;
|
||||
color: #475569;
|
||||
line-height: 1.5;
|
||||
margin-top: 4px;
|
||||
white-space: pre-line;
|
||||
}
|
||||
</style>
|
||||
61
templates/blocks/visuals/process-horizontal.html
Normal file
61
templates/blocks/visuals/process-horizontal.html
Normal file
@@ -0,0 +1,61 @@
|
||||
<!-- 프로세스 블록: 가로 단계 흐름 -->
|
||||
<div class="block-process">
|
||||
{% for step in steps %}
|
||||
<div class="process-step">
|
||||
<div class="process-number">{{ step.number | default(loop.index) }}</div>
|
||||
<div class="process-title">{{ step.title }}</div>
|
||||
{% if step.description %}<div class="process-desc">{{ step.description }}</div>{% endif %}
|
||||
</div>
|
||||
{% if not loop.last %}
|
||||
<div class="process-arrow">→</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-process {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--spacing-small);
|
||||
height: 100%;
|
||||
}
|
||||
.process-step {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: var(--spacing-inner);
|
||||
background: var(--color-bg-subtle);
|
||||
border: var(--border-width) solid var(--color-border);
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.process-number {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-accent);
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: var(--weight-bold);
|
||||
font-size: var(--font-body);
|
||||
margin: 0 auto var(--spacing-small);
|
||||
}
|
||||
.process-title {
|
||||
font-size: var(--font-body);
|
||||
font-weight: var(--weight-bold);
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.process-desc {
|
||||
font-size: var(--font-caption);
|
||||
color: var(--color-text-secondary);
|
||||
line-height: var(--line-height-ko);
|
||||
}
|
||||
.process-arrow {
|
||||
font-size: 1.5rem;
|
||||
color: var(--color-accent);
|
||||
font-weight: var(--weight-bold);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
125
templates/blocks/visuals/venn-diagram.html
Normal file
125
templates/blocks/visuals/venn-diagram.html
Normal file
@@ -0,0 +1,125 @@
|
||||
<!-- 벤 다이어그램: SVG premium (N개 자동 배치) -->
|
||||
<!--
|
||||
📋 venn-diagram (P2-B: 동적 좌표 계산)
|
||||
─────────────────
|
||||
용도: 상위-하위 포함 관계, 기술 융합 구조
|
||||
방식: renderer가 svg_calculator.prepare_venn_data()로 좌표 사전 계산
|
||||
→ items[].cx, cy, r + outer_r, center_x, center_y 전달
|
||||
Phase 1 fallback: outer_r이 없으면 3개 고정 좌표 사용
|
||||
-->
|
||||
<div class="block-venn-svg">
|
||||
{% if outer_r is defined %}
|
||||
{# ═══ P2-B: 동적 N개 배치 ═══ #}
|
||||
<svg viewBox="0 0 {{ viewbox_width | default(600) }} {{ viewbox_height | default(550) }}" width="100%" xmlns="http://www.w3.org/2000/svg" font-family="Pretendard Variable, sans-serif">
|
||||
<defs>
|
||||
<linearGradient id="bgGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#dce3ea" />
|
||||
<stop offset="100%" stop-color="#f0f2f5" />
|
||||
</linearGradient>
|
||||
<radialGradient id="blueOuter" cx="45%" cy="40%" r="55%">
|
||||
<stop offset="0%" stop-color="#2979ff" />
|
||||
<stop offset="40%" stop-color="#1565c0" />
|
||||
<stop offset="100%" stop-color="#0d47a1" />
|
||||
</radialGradient>
|
||||
<radialGradient id="hlGrad" cx="35%" cy="25%" r="40%">
|
||||
<stop offset="0%" stop-color="rgba(255,255,255,0.5)" />
|
||||
<stop offset="100%" stop-color="rgba(255,255,255,0)" />
|
||||
</radialGradient>
|
||||
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
|
||||
<feGaussianBlur stdDeviation="8" result="blur" />
|
||||
<feMerge><feMergeNode in="blur" /><feMergeNode in="SourceGraphic" /></feMerge>
|
||||
</filter>
|
||||
<filter id="shadow">
|
||||
<feDropShadow dx="0" dy="4" stdDeviation="8" flood-color="rgba(0,0,0,0.3)" />
|
||||
</filter>
|
||||
{% for item in items %}
|
||||
<radialGradient id="itemGrad{{ loop.index }}" cx="35%" cy="30%" r="65%">
|
||||
<stop offset="0%" stop-color="{{ item.color_light | default('#93c5fd') }}" />
|
||||
<stop offset="100%" stop-color="{{ item.color | default('#3b82f6') }}" />
|
||||
</radialGradient>
|
||||
{% endfor %}
|
||||
</defs>
|
||||
|
||||
<rect width="{{ viewbox_width | default(600) }}" height="{{ viewbox_height | default(550) }}" fill="url(#bgGrad)" />
|
||||
|
||||
<circle cx="{{ center_x }}" cy="{{ center_y }}" r="{{ outer_r }}" fill="url(#blueOuter)" filter="url(#shadow)" />
|
||||
<circle cx="{{ center_x }}" cy="{{ center_y }}" r="{{ outer_r - 10 }}" fill="none" stroke="#4a90d9" stroke-width="1.5" opacity="0.4" />
|
||||
<circle cx="{{ center_x }}" cy="{{ center_y }}" r="{{ outer_r - 25 }}" fill="none" stroke="#5a9de0" stroke-width="1" opacity="0.3" />
|
||||
<circle cx="{{ center_x }}" cy="{{ center_y }}" r="{{ outer_r - 40 }}" fill="none" stroke="#6aabe6" stroke-width="0.8" opacity="0.25" />
|
||||
|
||||
{% for item in items %}
|
||||
<circle cx="{{ item.cx }}" cy="{{ item.cy }}" r="{{ item.r }}" fill="url(#itemGrad{{ loop.index }})" opacity="0.9" filter="url(#glow)" />
|
||||
<circle cx="{{ item.cx }}" cy="{{ item.cy }}" r="{{ item.r }}" fill="url(#hlGrad)" />
|
||||
<text x="{{ item.cx }}" y="{{ item.cy }}" text-anchor="middle" dominant-baseline="central" fill="white" font-size="{% if item.r > 60 %}18{% elif item.r > 40 %}15{% else %}12{% endif %}" font-weight="700">{{ item.label }}</text>
|
||||
{% if item.sub %}
|
||||
<text x="{{ item.cx }}" y="{{ item.cy + 18 }}" text-anchor="middle" fill="white" font-size="11" opacity="0.85">{{ item.sub }}</text>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<text x="{{ center_x }}" y="{{ center_y - outer_r + 35 }}" text-anchor="middle" fill="#ffffff" font-size="13" font-weight="400" opacity="0.85">{{ center_sub | default('') }}</text>
|
||||
<text x="{{ center_x }}" y="{{ center_y - outer_r + 60 }}" text-anchor="middle" fill="#ffffff" font-size="24" font-weight="900">{{ center_label }}</text>
|
||||
</svg>
|
||||
|
||||
{% else %}
|
||||
{# ═══ Phase 1 fallback: 3개 고정 ═══ #}
|
||||
<svg viewBox="0 0 600 550" width="100%" xmlns="http://www.w3.org/2000/svg" font-family="Pretendard Variable, sans-serif">
|
||||
<defs>
|
||||
<linearGradient id="bgGrad" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#dce3ea" /><stop offset="100%" stop-color="#f0f2f5" /></linearGradient>
|
||||
<radialGradient id="blueOuter" cx="45%" cy="40%" r="55%"><stop offset="0%" stop-color="#2979ff" /><stop offset="40%" stop-color="#1565c0" /><stop offset="100%" stop-color="#0d47a1" /></radialGradient>
|
||||
<radialGradient id="orangeGrad" cx="35%" cy="35%" r="65%"><stop offset="0%" stop-color="#ffab40" /><stop offset="40%" stop-color="#ff6d00" /><stop offset="100%" stop-color="#c2185b" /></radialGradient>
|
||||
<radialGradient id="mintGrad" cx="40%" cy="30%" r="65%"><stop offset="0%" stop-color="#80deea" /><stop offset="40%" stop-color="#26c6da" /><stop offset="100%" stop-color="#00897b" /></radialGradient>
|
||||
<radialGradient id="goldGrad" cx="40%" cy="30%" r="65%"><stop offset="0%" stop-color="#ffd54f" /><stop offset="40%" stop-color="#ffb300" /><stop offset="100%" stop-color="#e65100" /></radialGradient>
|
||||
<radialGradient id="hlGrad" cx="35%" cy="25%" r="40%"><stop offset="0%" stop-color="rgba(255,255,255,0.5)" /><stop offset="100%" stop-color="rgba(255,255,255,0)" /></radialGradient>
|
||||
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%"><feGaussianBlur stdDeviation="8" result="blur" /><feMerge><feMergeNode in="blur" /><feMergeNode in="SourceGraphic" /></feMerge></filter>
|
||||
<filter id="shadow"><feDropShadow dx="0" dy="4" stdDeviation="8" flood-color="rgba(0,0,0,0.3)" /></filter>
|
||||
</defs>
|
||||
<rect width="600" height="550" fill="url(#bgGrad)" />
|
||||
<circle cx="300" cy="270" r="230" fill="url(#blueOuter)" filter="url(#shadow)" />
|
||||
<circle cx="300" cy="270" r="220" fill="none" stroke="#4a90d9" stroke-width="1.5" opacity="0.4" />
|
||||
<circle cx="300" cy="270" r="205" fill="none" stroke="#5a9de0" stroke-width="1" opacity="0.3" />
|
||||
<circle cx="300" cy="270" r="190" fill="none" stroke="#6aabe6" stroke-width="0.8" opacity="0.25" />
|
||||
<circle cx="265" cy="300" r="120" fill="url(#orangeGrad)" opacity="0.92" filter="url(#glow)" />
|
||||
<circle cx="265" cy="300" r="120" fill="url(#hlGrad)" />
|
||||
<circle cx="370" cy="230" r="75" fill="url(#mintGrad)" opacity="0.9" filter="url(#glow)" />
|
||||
<circle cx="370" cy="230" r="75" fill="url(#hlGrad)" />
|
||||
<circle cx="365" cy="355" r="75" fill="url(#goldGrad)" opacity="0.9" filter="url(#glow)" />
|
||||
<circle cx="365" cy="355" r="75" fill="url(#hlGrad)" />
|
||||
<text x="300" y="95" text-anchor="middle" fill="#ffffff" font-size="13" font-weight="400" opacity="0.85">{{ center_sub | default('') }}</text>
|
||||
<text x="300" y="125" text-anchor="middle" fill="#ffffff" font-size="26" font-weight="900">{{ center_label }}</text>
|
||||
{% if items and items | length > 0 %}<text x="250" y="295" text-anchor="middle" fill="#ffffff" font-size="20" font-weight="800">{{ items[0].label }}</text>{% if items[0].sub %}<text x="250" y="318" text-anchor="middle" fill="#ffffff" font-size="13" opacity="0.85">{{ items[0].sub }}</text>{% endif %}{% endif %}
|
||||
{% if items and items | length > 1 %}<text x="370" y="237" text-anchor="middle" fill="#ffffff" font-size="20" font-weight="800">{{ items[1].label }}</text>{% endif %}
|
||||
{% if items and items | length > 2 %}<text x="365" y="362" text-anchor="middle" fill="#ffffff" font-size="20" font-weight="800">{{ items[2].label }}</text>{% endif %}
|
||||
</svg>
|
||||
{% endif %}
|
||||
|
||||
{% if description %}
|
||||
<div class="venn-desc">{{ description }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.block-venn-svg {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 10px 0;
|
||||
flex-shrink: 1;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.block-venn-svg svg {
|
||||
max-width: 450px;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
.venn-desc {
|
||||
font-size: 14px;
|
||||
color: #444;
|
||||
text-align: center;
|
||||
max-width: 450px;
|
||||
line-height: 1.7;
|
||||
word-break: keep-all;
|
||||
}
|
||||
</style>
|
||||
1844
templates/catalog.yaml
Normal file
1844
templates/catalog.yaml
Normal file
File diff suppressed because it is too large
Load Diff
61
templates/slide-base.html
Normal file
61
templates/slide-base.html
Normal file
@@ -0,0 +1,61 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{ slide_title | default('슬라이드') }}</title>
|
||||
<link rel="stylesheet" href="/static/base.css">
|
||||
<style>
|
||||
{% for page in pages %}
|
||||
.slide-{{ page.page_number }} {
|
||||
grid-template-areas: {{ page.grid_areas }};
|
||||
grid-template-columns: {{ page.grid_columns | default('1fr') }};
|
||||
grid-template-rows: {{ page.grid_rows | default('auto 1fr auto') }};
|
||||
}
|
||||
{% for block in page.blocks %}
|
||||
.slide-{{ page.page_number }} .area-{{ block.area }} {
|
||||
grid-area: {{ block.area }};
|
||||
}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
/* 다중 페이지: 페이지 간 간격 */
|
||||
.slide + .slide {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
/* 인쇄 시 페이지 분리 */
|
||||
@media print {
|
||||
.slide {
|
||||
page-break-after: always;
|
||||
}
|
||||
.slide + .slide {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{% for page in pages %}
|
||||
<div class="slide slide-{{ page.page_number }}">
|
||||
{% if loop.first and slide_title %}
|
||||
<div class="slide-title" style="grid-area: header;">{{ slide_title }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% for block in page.blocks %}
|
||||
<div class="area-{{ block.area }}" style="{{ block.style_override | default('') }}">
|
||||
{{ block.html }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<script>
|
||||
/* 인쇄 시 <details> 자동 펼침, 인쇄 후 복원 */
|
||||
window.onbeforeprint = function() {
|
||||
document.querySelectorAll('details').forEach(function(d) { d.open = true; });
|
||||
};
|
||||
window.onafterprint = function() {
|
||||
document.querySelectorAll('details').forEach(function(d) { d.open = false; });
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user