slides-grab 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +80 -0
- package/LICENSE +21 -0
- package/PROGRESS.md +39 -0
- package/README.md +120 -0
- package/SETUP.md +51 -0
- package/bin/ppt-agent.js +204 -0
- package/convert.cjs +184 -0
- package/package.json +51 -0
- package/prd.json +135 -0
- package/prd.md +104 -0
- package/scripts/editor-server.js +779 -0
- package/scripts/html2pdf.js +217 -0
- package/scripts/validate-slides.js +416 -0
- package/skills/ppt-design-skill/SKILL.md +38 -0
- package/skills/ppt-plan-skill/SKILL.md +37 -0
- package/skills/ppt-pptx-skill/SKILL.md +37 -0
- package/skills/ppt-presentation-skill/SKILL.md +57 -0
- package/src/editor/codex-edit.js +213 -0
- package/src/editor/editor.html +1733 -0
- package/src/editor/js/editor-bbox.js +332 -0
- package/src/editor/js/editor-chat.js +56 -0
- package/src/editor/js/editor-direct-edit.js +110 -0
- package/src/editor/js/editor-dom.js +55 -0
- package/src/editor/js/editor-init.js +284 -0
- package/src/editor/js/editor-navigation.js +54 -0
- package/src/editor/js/editor-select.js +264 -0
- package/src/editor/js/editor-send.js +157 -0
- package/src/editor/js/editor-sse.js +163 -0
- package/src/editor/js/editor-state.js +32 -0
- package/src/editor/js/editor-utils.js +167 -0
- package/src/editor/screenshot.js +73 -0
- package/src/resolve.js +159 -0
- package/templates/chart.html +121 -0
- package/templates/closing.html +54 -0
- package/templates/content.html +50 -0
- package/templates/contents.html +60 -0
- package/templates/cover.html +64 -0
- package/templates/custom/.gitkeep +0 -0
- package/templates/custom/README.md +7 -0
- package/templates/diagram.html +98 -0
- package/templates/quote.html +31 -0
- package/templates/section-divider.html +43 -0
- package/templates/split-layout.html +41 -0
- package/templates/statistics.html +55 -0
- package/templates/team.html +49 -0
- package/templates/timeline.html +59 -0
- package/themes/corporate.css +8 -0
- package/themes/executive.css +10 -0
- package/themes/modern-dark.css +9 -0
- package/themes/sage.css +9 -0
- package/themes/warm.css +8 -0
package/src/resolve.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path resolution for slides-grab.
|
|
3
|
+
*
|
|
4
|
+
* Resolution order:
|
|
5
|
+
* 1. Local (user's CWD) — per-project overrides
|
|
6
|
+
* 2. Package root — built-in defaults
|
|
7
|
+
*
|
|
8
|
+
* slides directory, slide-outline.md, style-config.md → always local (CWD)
|
|
9
|
+
* templates/, themes/ → local first, package fallback
|
|
10
|
+
* scripts/ → always package
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
14
|
+
import { dirname, join, resolve } from 'node:path';
|
|
15
|
+
import { fileURLToPath } from 'node:url';
|
|
16
|
+
|
|
17
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
const PACKAGE_ROOT = resolve(__dirname, '..');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get the package root directory (where slides-grab is installed).
|
|
22
|
+
*/
|
|
23
|
+
export function getPackageRoot() {
|
|
24
|
+
return PACKAGE_ROOT;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get the user's working directory (where slides are created).
|
|
29
|
+
*/
|
|
30
|
+
export function getCwd() {
|
|
31
|
+
return process.cwd();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Resolve the slides directory in CWD.
|
|
36
|
+
* @param {string} [slidesDir='slides'] - relative or absolute slides directory path
|
|
37
|
+
*/
|
|
38
|
+
export function getSlidesDir(slidesDir = process.env.PPT_AGENT_SLIDES_DIR || 'slides') {
|
|
39
|
+
return resolve(getCwd(), slidesDir);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Resolve a template file. Local first, then package fallback.
|
|
44
|
+
* @param {string} name — template name without extension (e.g. "cover")
|
|
45
|
+
* @returns {{ path: string, source: 'local' | 'package' } | null}
|
|
46
|
+
*/
|
|
47
|
+
export function resolveTemplate(name) {
|
|
48
|
+
const fileName = name.endsWith('.html') ? name : `${name}.html`;
|
|
49
|
+
|
|
50
|
+
const localPath = join(getCwd(), 'templates', fileName);
|
|
51
|
+
if (existsSync(localPath)) {
|
|
52
|
+
return { path: localPath, source: 'local' };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const packagePath = join(PACKAGE_ROOT, 'templates', fileName);
|
|
56
|
+
if (existsSync(packagePath)) {
|
|
57
|
+
return { path: packagePath, source: 'package' };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Resolve a theme file. Local first, then package fallback.
|
|
65
|
+
* @param {string} name — theme name without extension (e.g. "modern-dark")
|
|
66
|
+
* @returns {{ path: string, source: 'local' | 'package' } | null}
|
|
67
|
+
*/
|
|
68
|
+
export function resolveTheme(name) {
|
|
69
|
+
const fileName = name.endsWith('.css') ? name : `${name}.css`;
|
|
70
|
+
|
|
71
|
+
const localPath = join(getCwd(), 'themes', fileName);
|
|
72
|
+
if (existsSync(localPath)) {
|
|
73
|
+
return { path: localPath, source: 'local' };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const packagePath = join(PACKAGE_ROOT, 'themes', fileName);
|
|
77
|
+
if (existsSync(packagePath)) {
|
|
78
|
+
return { path: packagePath, source: 'package' };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* List all available templates (local + package, deduplicated).
|
|
86
|
+
* @returns {Array<{ name: string, source: 'local' | 'package' }>}
|
|
87
|
+
*/
|
|
88
|
+
export function listTemplates() {
|
|
89
|
+
const seen = new Map();
|
|
90
|
+
|
|
91
|
+
// Local templates first (take priority)
|
|
92
|
+
const localDir = join(getCwd(), 'templates');
|
|
93
|
+
if (existsSync(localDir)) {
|
|
94
|
+
for (const f of readdirSync(localDir)) {
|
|
95
|
+
if (f.endsWith('.html')) {
|
|
96
|
+
seen.set(f, { name: f.replace('.html', ''), source: 'local' });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Also check local custom/ subdirectory
|
|
102
|
+
const localCustomDir = join(localDir, 'custom');
|
|
103
|
+
if (existsSync(localCustomDir)) {
|
|
104
|
+
for (const f of readdirSync(localCustomDir)) {
|
|
105
|
+
if (f.endsWith('.html')) {
|
|
106
|
+
const key = `custom/${f}`;
|
|
107
|
+
seen.set(key, { name: `custom/${f.replace('.html', '')}`, source: 'local' });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Package templates (only if not already overridden)
|
|
113
|
+
const pkgDir = join(PACKAGE_ROOT, 'templates');
|
|
114
|
+
if (existsSync(pkgDir)) {
|
|
115
|
+
for (const f of readdirSync(pkgDir)) {
|
|
116
|
+
if (f.endsWith('.html') && !seen.has(f)) {
|
|
117
|
+
seen.set(f, { name: f.replace('.html', ''), source: 'package' });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return Array.from(seen.values()).sort((a, b) => a.name.localeCompare(b.name));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* List all available themes (local + package, deduplicated).
|
|
127
|
+
* @returns {Array<{ name: string, source: 'local' | 'package' }>}
|
|
128
|
+
*/
|
|
129
|
+
export function listThemes() {
|
|
130
|
+
const seen = new Map();
|
|
131
|
+
|
|
132
|
+
const localDir = join(getCwd(), 'themes');
|
|
133
|
+
if (existsSync(localDir)) {
|
|
134
|
+
for (const f of readdirSync(localDir)) {
|
|
135
|
+
if (f.endsWith('.css')) {
|
|
136
|
+
seen.set(f, { name: f.replace('.css', ''), source: 'local' });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const pkgDir = join(PACKAGE_ROOT, 'themes');
|
|
142
|
+
if (existsSync(pkgDir)) {
|
|
143
|
+
for (const f of readdirSync(pkgDir)) {
|
|
144
|
+
if (f.endsWith('.css') && !seen.has(f)) {
|
|
145
|
+
seen.set(f, { name: f.replace('.css', ''), source: 'package' });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return Array.from(seen.values()).sort((a, b) => a.name.localeCompare(b.name));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Resolve a script path. Always from package.
|
|
155
|
+
* @param {string} relativePath — e.g. "scripts/validate-slides.js"
|
|
156
|
+
*/
|
|
157
|
+
export function resolveScript(relativePath) {
|
|
158
|
+
return join(PACKAGE_ROOT, relativePath);
|
|
159
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css">
|
|
5
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
6
|
+
<style>
|
|
7
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
8
|
+
body {
|
|
9
|
+
width: 720pt;
|
|
10
|
+
height: 405pt;
|
|
11
|
+
font-family: 'Pretendard', sans-serif;
|
|
12
|
+
background: #ffffff;
|
|
13
|
+
padding: 36pt 40pt;
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
color: #111827;
|
|
17
|
+
}
|
|
18
|
+
.chart-grid {
|
|
19
|
+
flex: 1;
|
|
20
|
+
display: grid;
|
|
21
|
+
grid-template-columns: repeat(3, 1fr);
|
|
22
|
+
gap: 14pt;
|
|
23
|
+
margin-top: 18pt;
|
|
24
|
+
}
|
|
25
|
+
.chart-card {
|
|
26
|
+
border: 1px solid #e5e7eb;
|
|
27
|
+
border-radius: 10pt;
|
|
28
|
+
padding: 10pt;
|
|
29
|
+
display: flex;
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
}
|
|
32
|
+
.chart-canvas-wrap {
|
|
33
|
+
flex: 1;
|
|
34
|
+
min-height: 0;
|
|
35
|
+
position: relative;
|
|
36
|
+
}
|
|
37
|
+
canvas {
|
|
38
|
+
width: 100% !important;
|
|
39
|
+
height: 100% !important;
|
|
40
|
+
}
|
|
41
|
+
</style>
|
|
42
|
+
</head>
|
|
43
|
+
<body>
|
|
44
|
+
<div style="display: flex; justify-content: space-between; align-items: baseline;">
|
|
45
|
+
<h2 style="font-size: 28pt; font-weight: 700; letter-spacing: -0.01em;">Quarterly Performance</h2>
|
|
46
|
+
<p style="font-size: 10pt; color: #6b7280;">DATA / CHART.JS</p>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<p style="font-size: 12pt; color: #4b5563; margin-top: 8pt;">
|
|
50
|
+
Bar, line, pie 차트를 하나의 슬라이드에서 비교하는 템플릿
|
|
51
|
+
</p>
|
|
52
|
+
|
|
53
|
+
<div class="chart-grid">
|
|
54
|
+
<div class="chart-card">
|
|
55
|
+
<p style="font-size: 10pt; color: #374151; margin-bottom: 6pt;">Bar Chart</p>
|
|
56
|
+
<div class="chart-canvas-wrap">
|
|
57
|
+
<canvas id="barChart"></canvas>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="chart-card">
|
|
61
|
+
<p style="font-size: 10pt; color: #374151; margin-bottom: 6pt;">Line Chart</p>
|
|
62
|
+
<div class="chart-canvas-wrap">
|
|
63
|
+
<canvas id="lineChart"></canvas>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
<div class="chart-card">
|
|
67
|
+
<p style="font-size: 10pt; color: #374151; margin-bottom: 6pt;">Pie Chart</p>
|
|
68
|
+
<div class="chart-canvas-wrap">
|
|
69
|
+
<canvas id="pieChart"></canvas>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<p style="font-size: 9pt; color: #9ca3af; margin-top: 10pt;">Source: Sample Dataset</p>
|
|
75
|
+
|
|
76
|
+
<script>
|
|
77
|
+
const labels = ['Q1', 'Q2', 'Q3', 'Q4'];
|
|
78
|
+
const values = [14, 22, 19, 27];
|
|
79
|
+
const colors = ['#2563eb', '#10b981', '#f59e0b', '#ef4444'];
|
|
80
|
+
const shared = { animation: false, responsive: true, maintainAspectRatio: false };
|
|
81
|
+
|
|
82
|
+
new Chart(document.getElementById('barChart'), {
|
|
83
|
+
type: 'bar',
|
|
84
|
+
data: { labels, datasets: [{ data: values, backgroundColor: colors, borderRadius: 4 }] },
|
|
85
|
+
options: {
|
|
86
|
+
...shared,
|
|
87
|
+
plugins: { legend: { display: false } },
|
|
88
|
+
scales: { y: { beginAtZero: true, grid: { color: '#e5e7eb' } } }
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
new Chart(document.getElementById('lineChart'), {
|
|
93
|
+
type: 'line',
|
|
94
|
+
data: {
|
|
95
|
+
labels,
|
|
96
|
+
datasets: [{
|
|
97
|
+
data: values,
|
|
98
|
+
borderColor: '#2563eb',
|
|
99
|
+
backgroundColor: 'rgba(37,99,235,0.15)',
|
|
100
|
+
fill: true,
|
|
101
|
+
tension: 0.35
|
|
102
|
+
}]
|
|
103
|
+
},
|
|
104
|
+
options: {
|
|
105
|
+
...shared,
|
|
106
|
+
plugins: { legend: { display: false } },
|
|
107
|
+
scales: { y: { beginAtZero: true, grid: { color: '#e5e7eb' } } }
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
new Chart(document.getElementById('pieChart'), {
|
|
112
|
+
type: 'pie',
|
|
113
|
+
data: { labels, datasets: [{ data: [34, 26, 21, 19], backgroundColor: colors }] },
|
|
114
|
+
options: {
|
|
115
|
+
...shared,
|
|
116
|
+
plugins: { legend: { position: 'bottom', labels: { boxWidth: 10, font: { size: 9 } } } }
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
</script>
|
|
120
|
+
</body>
|
|
121
|
+
</html>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css">
|
|
5
|
+
<style>
|
|
6
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
7
|
+
body {
|
|
8
|
+
width: 720pt;
|
|
9
|
+
height: 405pt;
|
|
10
|
+
font-family: 'Pretendard', sans-serif;
|
|
11
|
+
background: #1a1a1a;
|
|
12
|
+
padding: 48pt;
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
justify-content: space-between;
|
|
16
|
+
}
|
|
17
|
+
</style>
|
|
18
|
+
</head>
|
|
19
|
+
<body>
|
|
20
|
+
<!-- 로고 -->
|
|
21
|
+
<div style="display: flex; align-items: center; gap: 8pt;">
|
|
22
|
+
<div style="width: 20pt; height: 20pt; background: #fff; border-radius: 4pt; display: flex; align-items: center; justify-content: center;">
|
|
23
|
+
<p style="color: #1a1a1a; font-size: 12pt;">*</p>
|
|
24
|
+
</div>
|
|
25
|
+
<p style="font-size: 12pt; font-weight: 600; color: #ffffff;">LogoName</p>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<!-- 메인 메시지 -->
|
|
29
|
+
<div>
|
|
30
|
+
<h1 style="font-size: 56pt; font-weight: 500; color: #ffffff; letter-spacing: -0.02em; line-height: 1.1;">
|
|
31
|
+
Thank You
|
|
32
|
+
</h1>
|
|
33
|
+
<p style="font-size: 16pt; color: #888; margin-top: 16pt;">
|
|
34
|
+
Questions? Let's discuss.
|
|
35
|
+
</p>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<!-- 연락처 정보 -->
|
|
39
|
+
<div style="display: flex; gap: 64pt;">
|
|
40
|
+
<div>
|
|
41
|
+
<p style="font-size: 9pt; color: #666; margin-bottom: 4pt;">Email</p>
|
|
42
|
+
<p style="font-size: 12pt; font-weight: 500; color: #ffffff;">hello@company.com</p>
|
|
43
|
+
</div>
|
|
44
|
+
<div>
|
|
45
|
+
<p style="font-size: 9pt; color: #666; margin-bottom: 4pt;">Phone</p>
|
|
46
|
+
<p style="font-size: 12pt; font-weight: 500; color: #ffffff;">+82 10-1234-5678</p>
|
|
47
|
+
</div>
|
|
48
|
+
<div>
|
|
49
|
+
<p style="font-size: 9pt; color: #666; margin-bottom: 4pt;">Website</p>
|
|
50
|
+
<p style="font-size: 12pt; font-weight: 500; color: #ffffff;">www.company.com</p>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</body>
|
|
54
|
+
</html>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css">
|
|
5
|
+
<style>
|
|
6
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
7
|
+
body {
|
|
8
|
+
width: 720pt;
|
|
9
|
+
height: 405pt;
|
|
10
|
+
font-family: 'Pretendard', sans-serif;
|
|
11
|
+
background: #ffffff;
|
|
12
|
+
padding: 40pt 48pt;
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
}
|
|
16
|
+
</style>
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<!-- 헤더 -->
|
|
20
|
+
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 32pt;">
|
|
21
|
+
<div style="display: flex; align-items: center; gap: 12pt;">
|
|
22
|
+
<p style="display: inline-block; padding: 4pt 10pt; background: #1a1a1a; color: #fff; border-radius: 4pt; font-size: 8pt; font-weight: 600;">SECTION 1</p>
|
|
23
|
+
<h2 style="font-size: 24pt; font-weight: 600; color: #1a1a1a;">Main Topic</h2>
|
|
24
|
+
</div>
|
|
25
|
+
<p style="font-size: 10pt; color: #999;">02</p>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<!-- 콘텐츠 영역 -->
|
|
29
|
+
<div style="flex: 1; display: grid; grid-template-columns: 1fr 1fr; gap: 32pt;">
|
|
30
|
+
<div>
|
|
31
|
+
<h3 style="font-size: 18pt; font-weight: 600; color: #1a1a1a; margin-bottom: 16pt;">Key Point One</h3>
|
|
32
|
+
<p style="font-size: 13pt; color: #666; line-height: 1.7;">
|
|
33
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore.
|
|
34
|
+
</p>
|
|
35
|
+
</div>
|
|
36
|
+
<div>
|
|
37
|
+
<h3 style="font-size: 18pt; font-weight: 600; color: #1a1a1a; margin-bottom: 16pt;">Key Point Two</h3>
|
|
38
|
+
<p style="font-size: 13pt; color: #666; line-height: 1.7;">
|
|
39
|
+
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip.
|
|
40
|
+
</p>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<!-- 푸터 -->
|
|
45
|
+
<div style="display: flex; justify-content: space-between; align-items: center; padding-top: 16pt; border-top: 1px solid #eee;">
|
|
46
|
+
<p style="font-size: 9pt; color: #999;">www.yourwebsite.com</p>
|
|
47
|
+
<p style="font-size: 9pt; color: #999;">©2025 YOUR BRAND</p>
|
|
48
|
+
</div>
|
|
49
|
+
</body>
|
|
50
|
+
</html>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css">
|
|
5
|
+
<style>
|
|
6
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
7
|
+
body {
|
|
8
|
+
width: 720pt;
|
|
9
|
+
height: 405pt;
|
|
10
|
+
font-family: 'Pretendard', sans-serif;
|
|
11
|
+
background: #b8c4b8;
|
|
12
|
+
padding: 48pt;
|
|
13
|
+
display: grid;
|
|
14
|
+
grid-template-columns: 1fr 1.8fr;
|
|
15
|
+
gap: 48pt;
|
|
16
|
+
}
|
|
17
|
+
</style>
|
|
18
|
+
</head>
|
|
19
|
+
<body>
|
|
20
|
+
<!-- 왼쪽: 타이틀 -->
|
|
21
|
+
<div style="display: flex; flex-direction: column; justify-content: flex-end;">
|
|
22
|
+
<p style="font-size: 9pt; color: #3d3d3d; margin-bottom: 16pt;">©2025 YOUR BRAND. ALL RIGHTS RESERVED.</p>
|
|
23
|
+
<h1 style="font-size: 56pt; font-weight: 500; color: #1a1a1a; letter-spacing: -0.02em; line-height: 1.1;">
|
|
24
|
+
Our<br>Contents
|
|
25
|
+
</h1>
|
|
26
|
+
<div style="width: 32pt; height: 32pt; border: 1px solid #1a1a1a; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-top: 24pt;">
|
|
27
|
+
<p style="font-size: 14pt; color: #1a1a1a;">↗</p>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<!-- 오른쪽: 목차 리스트 -->
|
|
32
|
+
<div style="display: flex; flex-direction: column; justify-content: center; gap: 16pt;">
|
|
33
|
+
<div style="display: flex; align-items: center; gap: 16pt; padding: 12pt 0; border-bottom: 1px solid rgba(0,0,0,0.1);">
|
|
34
|
+
<p style="display: inline-block; padding: 4pt 10pt; background: #1a1a1a; color: #fff; border-radius: 4pt; font-size: 8pt; font-weight: 600;">SECTION 1</p>
|
|
35
|
+
<p style="flex: 1; font-size: 14pt; font-weight: 500; color: #1a1a1a;">SECTION TITLE</p>
|
|
36
|
+
<p style="font-size: 14pt; color: #666;">(1)</p>
|
|
37
|
+
</div>
|
|
38
|
+
<div style="display: flex; align-items: center; gap: 16pt; padding: 12pt 0; border-bottom: 1px solid rgba(0,0,0,0.1);">
|
|
39
|
+
<p style="display: inline-block; padding: 4pt 10pt; background: #1a1a1a; color: #fff; border-radius: 4pt; font-size: 8pt; font-weight: 600;">SECTION 2</p>
|
|
40
|
+
<p style="flex: 1; font-size: 14pt; font-weight: 500; color: #1a1a1a;">SECTION TITLE</p>
|
|
41
|
+
<p style="font-size: 14pt; color: #666;">(2)</p>
|
|
42
|
+
</div>
|
|
43
|
+
<div style="display: flex; align-items: center; gap: 16pt; padding: 12pt 0; border-bottom: 1px solid rgba(0,0,0,0.1);">
|
|
44
|
+
<p style="display: inline-block; padding: 4pt 10pt; background: #1a1a1a; color: #fff; border-radius: 4pt; font-size: 8pt; font-weight: 600;">SECTION 3</p>
|
|
45
|
+
<p style="flex: 1; font-size: 14pt; font-weight: 500; color: #1a1a1a;">SECTION TITLE</p>
|
|
46
|
+
<p style="font-size: 14pt; color: #666;">(3)</p>
|
|
47
|
+
</div>
|
|
48
|
+
<div style="display: flex; align-items: center; gap: 16pt; padding: 12pt 0; border-bottom: 1px solid rgba(0,0,0,0.1);">
|
|
49
|
+
<p style="display: inline-block; padding: 4pt 10pt; background: #1a1a1a; color: #fff; border-radius: 4pt; font-size: 8pt; font-weight: 600;">SECTION 4</p>
|
|
50
|
+
<p style="flex: 1; font-size: 14pt; font-weight: 500; color: #1a1a1a;">SECTION TITLE</p>
|
|
51
|
+
<p style="font-size: 14pt; color: #666;">(4)</p>
|
|
52
|
+
</div>
|
|
53
|
+
<div style="display: flex; align-items: center; gap: 16pt; padding: 12pt 0;">
|
|
54
|
+
<p style="display: inline-block; padding: 4pt 10pt; background: #1a1a1a; color: #fff; border-radius: 4pt; font-size: 8pt; font-weight: 600;">SECTION 5</p>
|
|
55
|
+
<p style="flex: 1; font-size: 14pt; font-weight: 500; color: #1a1a1a;">SECTION TITLE</p>
|
|
56
|
+
<p style="font-size: 14pt; color: #666;">(5)</p>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</body>
|
|
60
|
+
</html>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css">
|
|
5
|
+
<style>
|
|
6
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
7
|
+
body {
|
|
8
|
+
width: 720pt;
|
|
9
|
+
height: 405pt;
|
|
10
|
+
font-family: 'Pretendard', sans-serif;
|
|
11
|
+
background: #f5f5f0;
|
|
12
|
+
padding: 32pt 48pt;
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
}
|
|
16
|
+
</style>
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<!-- 헤더 -->
|
|
20
|
+
<div style="display: flex; justify-content: space-between; align-items: center;">
|
|
21
|
+
<div style="display: flex; align-items: center; gap: 16pt;">
|
|
22
|
+
<div style="display: flex; align-items: center; gap: 8pt;">
|
|
23
|
+
<div style="width: 18pt; height: 18pt; background: #1a1a1a; border-radius: 3pt; display: flex; align-items: center; justify-content: center;">
|
|
24
|
+
<p style="color: #fff; font-size: 10pt;">*</p>
|
|
25
|
+
</div>
|
|
26
|
+
<p style="font-size: 11pt; font-weight: 600; color: #1a1a1a;">LogoName</p>
|
|
27
|
+
</div>
|
|
28
|
+
<p style="display: inline-block; padding: 4pt 10pt; border: 1px solid #1a1a1a; border-radius: 12pt; font-size: 9pt; font-weight: 500;">PRESENTATION</p>
|
|
29
|
+
</div>
|
|
30
|
+
<div style="display: flex; align-items: center; gap: 8pt;">
|
|
31
|
+
<p style="display: inline-block; padding: 4pt 10pt; border: 1px solid #1a1a1a; border-radius: 12pt; font-size: 9pt; font-weight: 500;">OUR PROJECT</p>
|
|
32
|
+
<div style="width: 28pt; height: 28pt; border: 1px solid #1a1a1a; border-radius: 50%; display: flex; align-items: center; justify-content: center;">
|
|
33
|
+
<p style="font-size: 12pt; color: #1a1a1a;">↘</p>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<!-- 메인 타이틀 -->
|
|
39
|
+
<div style="flex: 1; display: flex; flex-direction: column; justify-content: center;">
|
|
40
|
+
<h1 style="font-size: 72pt; font-weight: 500; color: #1a1a1a; letter-spacing: -0.02em; line-height: 1.1;">
|
|
41
|
+
Business Deck
|
|
42
|
+
</h1>
|
|
43
|
+
<p style="font-size: 14pt; color: #666; margin-top: 24pt;">
|
|
44
|
+
<span style="color: #999;">Presented by</span> <span style="font-weight: 500; color: #1a1a1a;">Luna Martinez</span>
|
|
45
|
+
</p>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<!-- 푸터 정보 -->
|
|
49
|
+
<div style="display: flex; gap: 64pt;">
|
|
50
|
+
<div>
|
|
51
|
+
<p style="font-size: 9pt; color: #999; margin-bottom: 4pt;">Contact</p>
|
|
52
|
+
<p style="font-size: 11pt; font-weight: 500; color: #1a1a1a;">334556774</p>
|
|
53
|
+
</div>
|
|
54
|
+
<div>
|
|
55
|
+
<p style="font-size: 9pt; color: #999; margin-bottom: 4pt;">Date</p>
|
|
56
|
+
<p style="font-size: 11pt; font-weight: 500; color: #1a1a1a;">March 2025</p>
|
|
57
|
+
</div>
|
|
58
|
+
<div>
|
|
59
|
+
<p style="font-size: 9pt; color: #999; margin-bottom: 4pt;">Website</p>
|
|
60
|
+
<p style="font-size: 11pt; font-weight: 500; color: #1a1a1a;">www.yourwebsite.com</p>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</body>
|
|
64
|
+
</html>
|
|
File without changes
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css">
|
|
5
|
+
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
|
|
6
|
+
<style>
|
|
7
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
8
|
+
body {
|
|
9
|
+
width: 720pt;
|
|
10
|
+
height: 405pt;
|
|
11
|
+
font-family: 'Pretendard', sans-serif;
|
|
12
|
+
background: #ffffff;
|
|
13
|
+
padding: 36pt 40pt;
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
color: #111827;
|
|
17
|
+
}
|
|
18
|
+
.diagram-grid {
|
|
19
|
+
flex: 1;
|
|
20
|
+
min-height: 0;
|
|
21
|
+
display: grid;
|
|
22
|
+
grid-template-columns: 1fr 1fr;
|
|
23
|
+
gap: 14pt;
|
|
24
|
+
margin-top: 18pt;
|
|
25
|
+
}
|
|
26
|
+
.diagram-card {
|
|
27
|
+
border: 1px solid #e5e7eb;
|
|
28
|
+
border-radius: 10pt;
|
|
29
|
+
padding: 10pt;
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: column;
|
|
32
|
+
min-height: 0;
|
|
33
|
+
}
|
|
34
|
+
.diagram-wrap {
|
|
35
|
+
flex: 1;
|
|
36
|
+
min-height: 0;
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
}
|
|
39
|
+
pre.mermaid {
|
|
40
|
+
width: 100%;
|
|
41
|
+
height: 100%;
|
|
42
|
+
font-family: 'Pretendard', sans-serif;
|
|
43
|
+
background: #ffffff;
|
|
44
|
+
}
|
|
45
|
+
</style>
|
|
46
|
+
</head>
|
|
47
|
+
<body>
|
|
48
|
+
<div style="display: flex; justify-content: space-between; align-items: baseline;">
|
|
49
|
+
<h2 style="font-size: 28pt; font-weight: 700; letter-spacing: -0.01em;">Process Diagram</h2>
|
|
50
|
+
<p style="font-size: 10pt; color: #6b7280;">DIAGRAM / MERMAID</p>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<p style="font-size: 12pt; color: #4b5563; margin-top: 8pt;">
|
|
54
|
+
Flowchart와 sequence diagram을 한 장에 배치하는 템플릿
|
|
55
|
+
</p>
|
|
56
|
+
|
|
57
|
+
<div class="diagram-grid">
|
|
58
|
+
<div class="diagram-card">
|
|
59
|
+
<p style="font-size: 10pt; color: #374151; margin-bottom: 6pt;">Flowchart</p>
|
|
60
|
+
<div class="diagram-wrap">
|
|
61
|
+
<pre class="mermaid">
|
|
62
|
+
flowchart TD
|
|
63
|
+
A[요청 수신] --> B[아웃라인 생성]
|
|
64
|
+
B --> C[디자인 슬라이드 생성]
|
|
65
|
+
C --> D[PPTX 변환]
|
|
66
|
+
D --> E[검토]
|
|
67
|
+
</pre>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
<div class="diagram-card">
|
|
71
|
+
<p style="font-size: 10pt; color: #374151; margin-bottom: 6pt;">Sequence Diagram</p>
|
|
72
|
+
<div class="diagram-wrap">
|
|
73
|
+
<pre class="mermaid">
|
|
74
|
+
sequenceDiagram
|
|
75
|
+
participant User
|
|
76
|
+
participant Agent
|
|
77
|
+
participant Converter
|
|
78
|
+
User->>Agent: 슬라이드 생성 요청
|
|
79
|
+
Agent->>Converter: HTML 전달
|
|
80
|
+
Converter-->>Agent: PPTX 반환
|
|
81
|
+
Agent-->>User: 결과 전달
|
|
82
|
+
</pre>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<p style="font-size: 9pt; color: #9ca3af; margin-top: 10pt;">Rendered with Mermaid</p>
|
|
88
|
+
|
|
89
|
+
<script>
|
|
90
|
+
mermaid.initialize({
|
|
91
|
+
startOnLoad: true,
|
|
92
|
+
securityLevel: 'loose',
|
|
93
|
+
theme: 'default',
|
|
94
|
+
fontFamily: 'Pretendard'
|
|
95
|
+
});
|
|
96
|
+
</script>
|
|
97
|
+
</body>
|
|
98
|
+
</html>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css">
|
|
5
|
+
<style>
|
|
6
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
7
|
+
body {
|
|
8
|
+
width: 720pt;
|
|
9
|
+
height: 405pt;
|
|
10
|
+
font-family: 'Pretendard', sans-serif;
|
|
11
|
+
background: #1a1a1a;
|
|
12
|
+
padding: 64pt;
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
align-items: center;
|
|
17
|
+
text-align: center;
|
|
18
|
+
}
|
|
19
|
+
</style>
|
|
20
|
+
</head>
|
|
21
|
+
<body>
|
|
22
|
+
<p style="font-size: 48pt; color: #444; margin-bottom: 24pt;">"</p>
|
|
23
|
+
<h2 style="font-size: 28pt; font-weight: 400; color: #ffffff; letter-spacing: -0.01em; line-height: 1.5; max-width: 540pt;">
|
|
24
|
+
The best way to predict the future is to create it.
|
|
25
|
+
</h2>
|
|
26
|
+
<div style="margin-top: 40pt;">
|
|
27
|
+
<p style="font-size: 13pt; font-weight: 500; color: #ffffff;">Peter Drucker</p>
|
|
28
|
+
<p style="font-size: 11pt; color: #666; margin-top: 4pt;">Management Consultant</p>
|
|
29
|
+
</div>
|
|
30
|
+
</body>
|
|
31
|
+
</html>
|