@lemonppt/renderer 0.2.0 → 0.2.2

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.
Files changed (72) hide show
  1. package/dist/client/client-render.js +65 -5401
  2. package/dist/client/editor-script.js +3355 -0
  3. package/dist/client/theme-echarts.js +65 -25
  4. package/dist/client-render.d.ts +1 -7
  5. package/dist/client-render.d.ts.map +1 -1
  6. package/dist/client-render.js +1 -11
  7. package/dist/client-render.js.map +1 -1
  8. package/dist/editor-script.d.ts +1 -1
  9. package/dist/editor-script.d.ts.map +1 -1
  10. package/dist/editor-script.js +80 -77
  11. package/dist/editor-script.js.map +1 -1
  12. package/dist/export-pdf.js +1 -1
  13. package/dist/export-pdf.js.map +1 -1
  14. package/dist/export-pptx.d.ts +1132 -2
  15. package/dist/export-pptx.d.ts.map +1 -1
  16. package/dist/export-pptx.js +1208 -19525
  17. package/dist/export-pptx.js.map +1 -1
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1 -0
  21. package/dist/index.js.map +1 -1
  22. package/dist/render-editor-data.d.ts +21 -0
  23. package/dist/render-editor-data.d.ts.map +1 -0
  24. package/dist/render-editor-data.js +1068 -0
  25. package/dist/render-editor-data.js.map +1 -0
  26. package/dist/render.d.ts +0 -2
  27. package/dist/render.d.ts.map +1 -1
  28. package/dist/render.js +7 -323
  29. package/dist/render.js.map +1 -1
  30. package/dist/theme01-pptx.d.ts +12 -0
  31. package/dist/theme01-pptx.d.ts.map +1 -0
  32. package/dist/theme01-pptx.js +2954 -0
  33. package/dist/theme01-pptx.js.map +1 -0
  34. package/dist/theme02-pptx.d.ts +5 -0
  35. package/dist/theme02-pptx.d.ts.map +1 -0
  36. package/dist/theme02-pptx.js +1063 -0
  37. package/dist/theme02-pptx.js.map +1 -0
  38. package/dist/theme03-pptx.d.ts +5 -0
  39. package/dist/theme03-pptx.d.ts.map +1 -0
  40. package/dist/theme03-pptx.js +3279 -0
  41. package/dist/theme03-pptx.js.map +1 -0
  42. package/dist/theme04-pptx.d.ts +6 -0
  43. package/dist/theme04-pptx.d.ts.map +1 -0
  44. package/dist/theme04-pptx.js +5496 -0
  45. package/dist/theme04-pptx.js.map +1 -0
  46. package/dist/theme05-pptx.d.ts +5 -0
  47. package/dist/theme05-pptx.d.ts.map +1 -0
  48. package/dist/theme05-pptx.js +3152 -0
  49. package/dist/theme05-pptx.js.map +1 -0
  50. package/dist/theme06-pptx.d.ts +124 -0
  51. package/dist/theme06-pptx.d.ts.map +1 -0
  52. package/dist/theme06-pptx.js +8154 -0
  53. package/dist/theme06-pptx.js.map +1 -0
  54. package/dist/theme07-pptx.d.ts +49 -0
  55. package/dist/theme07-pptx.d.ts.map +1 -0
  56. package/dist/theme07-pptx.js +2579 -0
  57. package/dist/theme07-pptx.js.map +1 -0
  58. package/dist/theme08-pptx.d.ts +19 -0
  59. package/dist/theme08-pptx.d.ts.map +1 -0
  60. package/dist/theme08-pptx.js +1411 -0
  61. package/dist/theme08-pptx.js.map +1 -0
  62. package/dist/theme09-pptx.d.ts +18 -0
  63. package/dist/theme09-pptx.d.ts.map +1 -0
  64. package/dist/theme09-pptx.js +1513 -0
  65. package/dist/theme09-pptx.js.map +1 -0
  66. package/dist/theme10-pptx.d.ts +18 -0
  67. package/dist/theme10-pptx.d.ts.map +1 -0
  68. package/dist/theme10-pptx.js +2889 -0
  69. package/dist/theme10-pptx.js.map +1 -0
  70. package/package.json +7 -6
  71. package/templates/editor.html +580 -0
  72. package/templates/editor.js +222 -0
@@ -0,0 +1,1068 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { normalizeDeckGoal } from '@lemonppt/core';
3
+ import { renderSlide, generateThemeCssVariablesWithDark, generateTheme02CssVariablesWithSchemes, generateTheme03CssVariablesWithSchemes, generateTheme04CssVariablesWithTonesAndAppearance, generateTheme05CssVariablesWithSchemesAndAppearance, generateTheme06CssVariablesWithSchemesAndAppearance, generateTheme07CssVariablesWithSchemesAndAppearance, generateTheme08CssVariablesWithSchemesAndAppearance, generateTheme09CssVariablesWithSchemesAndAppearance, generateTheme10CssVariables, } from '@lemonppt/templates';
4
+ import ReactDOMServer from 'react-dom/server';
5
+ function resolveThemeMeta(goal) {
6
+ const theme = goal.theme || 'theme01';
7
+ const colorScheme = goal.colorScheme ||
8
+ (theme === 'theme02' || theme === 'theme03'
9
+ ? 'scheme-a'
10
+ : theme === 'theme04'
11
+ ? 'green'
12
+ : theme === 'theme05'
13
+ ? 'coral'
14
+ : theme === 'theme06'
15
+ ? 'volt'
16
+ : theme === 'theme07'
17
+ ? 'cold-white'
18
+ : theme === 'theme08'
19
+ ? 'obsidian-gold'
20
+ : theme === 'theme09'
21
+ ? 'ink-editorial'
22
+ : theme === 'theme10'
23
+ ? 'gold-index'
24
+ : 'light');
25
+ const appearance = goal.appearance ||
26
+ (theme === 'theme03' || theme === 'theme04' || theme === 'theme05' || theme === 'theme06'
27
+ ? 'dark'
28
+ : theme === 'theme07'
29
+ ? 'light'
30
+ : theme === 'theme08' || theme === 'theme09' || theme === 'theme10'
31
+ ? 'primary'
32
+ : undefined);
33
+ const themeCssVars = theme === 'theme01'
34
+ ? generateThemeCssVariablesWithDark()
35
+ : theme === 'theme02'
36
+ ? generateTheme02CssVariablesWithSchemes()
37
+ : theme === 'theme03'
38
+ ? generateTheme03CssVariablesWithSchemes()
39
+ : theme === 'theme04'
40
+ ? generateTheme04CssVariablesWithTonesAndAppearance()
41
+ : theme === 'theme05'
42
+ ? generateTheme05CssVariablesWithSchemesAndAppearance()
43
+ : theme === 'theme06'
44
+ ? generateTheme06CssVariablesWithSchemesAndAppearance()
45
+ : theme === 'theme07'
46
+ ? generateTheme07CssVariablesWithSchemesAndAppearance()
47
+ : theme === 'theme08'
48
+ ? generateTheme08CssVariablesWithSchemesAndAppearance()
49
+ : theme === 'theme09'
50
+ ? generateTheme09CssVariablesWithSchemesAndAppearance()
51
+ : theme === 'theme10'
52
+ ? generateTheme10CssVariables()
53
+ : '';
54
+ return { theme, colorScheme, appearance, themeCssVars };
55
+ }
56
+ /**
57
+ * 根据 goal 生成单页编辑器所需数据。
58
+ * 返回的各字段可直接注入统一的 editor.html 模板,不再为每个主题单独生成完整页面。
59
+ */
60
+ export function renderEditorData(goal, options = {}) {
61
+ goal = normalizeDeckGoal(goal);
62
+ const { width = 1280, height = 720 } = options;
63
+ const slideElements = goal.slides.map((slide, index) => {
64
+ const element = renderSlide(slide, { slideIdx: index, editable: true, theme: goal.theme });
65
+ const stateClass = index === 0 ? 'active' : '';
66
+ return (_jsx("div", { className: `lp-slide-wrapper ${stateClass}`, "data-slide-index": index, "data-layout": slide.layout, "data-lp-transition": String(slide.props.transition || 'none'), style: { width: `${width}px`, height: `${height}px`, boxSizing: 'border-box' }, children: element ?? _jsxs("div", { className: "lp-error", children: ["\u672A\u627E\u5230\u7248\u5F0F: ", slide.layout] }) }, index));
67
+ });
68
+ const slidesMarkup = ReactDOMServer.renderToStaticMarkup(_jsx("div", { className: "lp-deck", "data-theme": goal.theme, "data-lp-transition": "none", "data-editable": "true", style: { width: `${width}px`, height: `${height}px` }, children: slideElements }));
69
+ const slideHtmls = goal.slides.map((slide, index) => {
70
+ const element = renderSlide(slide, { slideIdx: index, editable: true, theme: goal.theme });
71
+ return ReactDOMServer.renderToStaticMarkup(_jsx("div", { style: { width: `${width}px`, height: `${height}px`, boxSizing: 'border-box' }, children: element ?? _jsxs("div", { className: "lp-error", children: ["\u672A\u627E\u5230\u7248\u5F0F: ", slide.layout] }) }));
72
+ });
73
+ const { theme, colorScheme, appearance, themeCssVars } = resolveThemeMeta(goal);
74
+ return {
75
+ goal,
76
+ theme,
77
+ colorScheme,
78
+ appearance,
79
+ slidesMarkup,
80
+ slideHtmls,
81
+ themeCssVars,
82
+ editorBarMarkup: '',
83
+ leftPanelMarkup: '',
84
+ rightPanelMarkup: '',
85
+ addSlideModalMarkup: '',
86
+ editorScriptMarkup: '',
87
+ };
88
+ }
89
+ function escapeHtml(text) {
90
+ return text
91
+ .replace(/&/g, '&')
92
+ .replace(/</g, '&lt;')
93
+ .replace(/>/g, '&gt;')
94
+ .replace(/"/g, '&quot;')
95
+ .replace(/'/g, '&#39;');
96
+ }
97
+ function buildEditorBarMarkup(goal) {
98
+ const appearance = goal.appearance || 'primary';
99
+ const appearanceButtons = [
100
+ { value: 'primary', label: '亮', icon: '☀' },
101
+ { value: 'dark', label: '暗', icon: '☾' },
102
+ { value: 'contrast', label: '彩', icon: '◐' },
103
+ ]
104
+ .map((btn) => `<button type="button" class="lp-appearance-btn ${btn.value === appearance ? 'lp-appearance-active' : ''}" data-appearance="${btn.value}"><span class="lp-appearance-icon">${btn.icon}</span><span class="lp-appearance-label">${btn.label}</span></button>`)
105
+ .join('');
106
+ return `<div class="lp-editor-bar" data-appearance="${appearance}">
107
+ <div class="lp-editor-title">${escapeHtml(goal.title || 'Untitled')}</div>
108
+ <div class="lp-appearance-switcher">${appearanceButtons}</div>
109
+ <select id="lp-theme-select" class="lp-editor-select" title="切换主题">
110
+ <option value="theme01" ${goal.theme === 'theme01' ? 'selected' : ''}>Theme 01</option>
111
+ <option value="theme02" ${goal.theme === 'theme02' ? 'selected' : ''}>Theme 02</option>
112
+ <option value="theme03" ${goal.theme === 'theme03' ? 'selected' : ''}>Theme 03</option>
113
+ <option value="theme04" ${goal.theme === 'theme04' ? 'selected' : ''}>Theme 04</option>
114
+ <option value="theme05" ${goal.theme === 'theme05' ? 'selected' : ''}>Theme 05</option>
115
+ <option value="theme06" ${goal.theme === 'theme06' ? 'selected' : ''}>Theme 06</option>
116
+ <option value="theme07" ${goal.theme === 'theme07' ? 'selected' : ''}>Theme 07</option>
117
+ <option value="theme08" ${goal.theme === 'theme08' ? 'selected' : ''}>Theme 08</option>
118
+ <option value="theme09" ${goal.theme === 'theme09' ? 'selected' : ''}>Theme 09</option>
119
+ <option value="theme10" ${goal.theme === 'theme10' ? 'selected' : ''}>Theme 10</option>
120
+ </select>
121
+ <button id="lp-add-slide" class="lp-editor-btn" type="button"><span>+</span> 添加页面</button>
122
+ <button id="lp-save-deck" class="lp-editor-btn lp-editor-btn-primary" type="button">保存</button>
123
+ <div class="lp-editor-export">
124
+ <button id="lp-export-toggle" class="lp-editor-btn lp-editor-export-toggle" type="button"><span>⬇</span> 导出 <span class="lp-editor-caret">▼</span></button>
125
+ <div id="lp-export-menu" class="lp-editor-export-menu" hidden>
126
+ <button class="lp-editor-export-item" data-format="html"><span class="lp-editor-export-icon">🌐</span><span class="lp-editor-export-label">HTML 演示</span><span class="lp-editor-export-tag">在线播放</span></button>
127
+ <button class="lp-editor-export-item" data-format="pdf"><span class="lp-editor-export-icon">📄</span><span class="lp-editor-export-label">PDF</span><span class="lp-editor-export-tag">打印/分享</span></button>
128
+ <button class="lp-editor-export-item" data-format="pptx"><span class="lp-editor-export-icon">📊</span><span class="lp-editor-export-label">PowerPoint</span><span class="lp-editor-export-tag">.pptx</span></button>
129
+ </div>
130
+ </div>
131
+ </div>`;
132
+ }
133
+ function buildLeftPanelMarkup(goal) {
134
+ const slideCount = goal.slides.length;
135
+ const thumbnails = goal.slides
136
+ .map((slide, index) => {
137
+ const activeClass = index === 0 ? ' active' : '';
138
+ return `<div class="lp-thumbnail${activeClass}" tabindex="0" draggable="true" data-slide-index="${index}" data-layout="${slide.layout}">
139
+ <div class="lp-thumbnail-drag-handle" aria-hidden="true">⋮⋮</div>
140
+ <div class="lp-thumbnail-index">${index + 1} / ${slideCount}</div>
141
+ <div class="lp-thumbnail-title">${slide.props.title ? escapeHtml(String(slide.props.title)) : `Slide ${index + 1}`}</div>
142
+ <div class="lp-thumbnail-layout">${slide.layout}</div>
143
+ <div class="lp-thumbnail-drop-indicator" data-drop-position="before"></div>
144
+ <div class="lp-thumbnail-drop-indicator" data-drop-position="after"></div>
145
+ </div>`;
146
+ })
147
+ .join('\n');
148
+ return `<aside class="lp-editor-left-panel">
149
+ <div class="lp-editor-thumbnails" id="lp-thumbnails">
150
+ ${thumbnails}
151
+ </div>
152
+ </aside>`;
153
+ }
154
+ function buildRightPanelMarkup() {
155
+ return `<aside class="lp-editor-right-panel">
156
+ <div class="lp-property-header">属性面板</div>
157
+ <div class="lp-property-empty">点击左侧缩略图选择幻灯片,然后编辑内容。</div>
158
+ </aside>`;
159
+ }
160
+ function buildAddSlideModalMarkup(goal) {
161
+ const layouts = goal.slides.length > 0 ? Array.from(new Set(goal.slides.map((s) => s.layout))) : ['title', 'content', 'section', 'closing'];
162
+ const layoutItems = layouts
163
+ .map((layout) => `<div class="lp-add-slide-item" data-layout="${layout}"><span class="lp-add-slide-item-icon">⊞</span><span class="lp-add-slide-item-label">${layout}</span></div>`)
164
+ .join('\n');
165
+ return `<div id="lp-add-slide-modal" class="lp-add-slide-modal-overlay">
166
+ <div class="lp-add-slide-modal">
167
+ <div class="lp-add-slide-modal-header"><span class="lp-add-slide-modal-title">添加幻灯片</span><button id="lp-add-slide-close" class="lp-add-slide-modal-close" type="button">×</button></div>
168
+ <div class="lp-add-slide-modal-body">
169
+ <div class="lp-add-slide-section-title">选择版式</div>
170
+ <div class="lp-add-slide-grid">
171
+ ${layoutItems}
172
+ </div>
173
+ </div>
174
+ </div>
175
+ </div>`;
176
+ }
177
+ function buildEditorScriptMarkup(goal) {
178
+ return `<script>
179
+ window.__lemonPPT_goal = ${JSON.stringify(goal)};
180
+ </script>
181
+ <script src="./assets/editor-script.js"></script>`;
182
+ }
183
+ /**
184
+ * 补全 EditorData 中的 UI 片段字段。
185
+ * 将渲染数据与 UI 组件解耦,方便服务端返回纯数据。
186
+ */
187
+ export function fillEditorDataUi(data) {
188
+ return {
189
+ ...data,
190
+ editorBarMarkup: buildEditorBarMarkup(data.goal),
191
+ leftPanelMarkup: buildLeftPanelMarkup(data.goal),
192
+ rightPanelMarkup: buildRightPanelMarkup(),
193
+ addSlideModalMarkup: buildAddSlideModalMarkup(data.goal),
194
+ editorScriptMarkup: buildEditorScriptMarkup(data.goal),
195
+ };
196
+ }
197
+ /**
198
+ * 将 EditorData 组装成完整 HTML 页面。
199
+ * 这是为兼容旧版 renderDeck(editable: true) 保留的封装。
200
+ */
201
+ export function renderEditorHtmlFromData(data, options = {}) {
202
+ const { width = 1280 } = options;
203
+ const { goal, theme, colorScheme, appearance, slidesMarkup, themeCssVars, editorBarMarkup, leftPanelMarkup, rightPanelMarkup, addSlideModalMarkup, editorScriptMarkup } = fillEditorDataUi(data);
204
+ const slideCount = goal.slides.length;
205
+ const appearanceAttr = appearance ? ` data-appearance="${appearance}"` : '';
206
+ const bodyMarkup = `<div class="lp-editor-root">
207
+ ${editorBarMarkup}
208
+ <div class="lp-editor-workspace">
209
+ ${leftPanelMarkup}
210
+ <main class="lp-editor-stage">
211
+ <div class="lp-editor-stage-scaler">
212
+ ${slidesMarkup}
213
+ <div class="lp-editor-page-counter"><span id="lp-current">1</span> / ${slideCount}</div>
214
+ </div>
215
+ <div class="lp-editor-zoom-bar">
216
+ <button id="lp-zoom-out" title="缩小">-</button>
217
+ <input type="range" id="lp-zoom-slider" min="35" max="150" value="100">
218
+ <button id="lp-zoom-in" title="放大">+</button>
219
+ <button id="lp-zoom-fit" title="适应画布">适应</button>
220
+ <span id="lp-zoom-value">100%</span>
221
+ </div>
222
+ </main>
223
+ ${rightPanelMarkup}
224
+ </div>
225
+ ${addSlideModalMarkup}
226
+ ${editorScriptMarkup}
227
+ </div>`;
228
+ const html = `<!DOCTYPE html>
229
+ <html lang="${goal.language ?? 'zh'}" data-theme="${colorScheme}"${appearanceAttr}>
230
+ <head>
231
+ <meta charset="UTF-8">
232
+ <meta name="viewport" content="width=${width}, initial-scale=1.0">
233
+ <title>${escapeHtml(goal.title)}</title>
234
+ <link rel="stylesheet" href="./assets/fonts/fonts.css">
235
+ <link rel="stylesheet" href="./assets/${theme}.css">
236
+ <script src="./assets/jquery.min.js"></script>
237
+ <style>
238
+ * { margin: 0; padding: 0; box-sizing: border-box; }
239
+ ${themeCssVars}
240
+ html, body {
241
+ width: 100%;
242
+ height: 100%;
243
+ background: #111;
244
+ }
245
+ body {
246
+ display: flex;
247
+ align-items: center;
248
+ justify-content: center;
249
+ }
250
+ .lp-editor-body {
251
+ display: block;
252
+ }
253
+ .lp-deck {
254
+ box-shadow: 0 24px 80px rgba(0,0,0,0.5);
255
+ border-radius: 12px;
256
+ overflow: hidden;
257
+ }
258
+ .lp-error {
259
+ width: 100%;
260
+ height: 100%;
261
+ display: flex;
262
+ align-items: center;
263
+ justify-content: center;
264
+ background: #fee2e2;
265
+ color: #991b1b;
266
+ font-family: system-ui, sans-serif;
267
+ }
268
+ .lp-editor-root {
269
+ display: flex;
270
+ flex-direction: column;
271
+ width: 100vw;
272
+ height: 100vh;
273
+ background: #1a1a1a;
274
+ color: #e5e5e5;
275
+ overflow: hidden;
276
+ }
277
+ .lp-editor-root .lp-editor-bar {
278
+ position: relative !important;
279
+ top: auto !important;
280
+ left: auto !important;
281
+ transform: none !important;
282
+ width: 100% !important;
283
+ height: 64px !important;
284
+ box-sizing: border-box !important;
285
+ border-radius: 0 !important;
286
+ border-bottom: 1px solid #333 !important;
287
+ background: #1e1e1e !important;
288
+ color: #e5e5e5 !important;
289
+ padding: 0 16px !important;
290
+ display: flex !important;
291
+ align-items: center !important;
292
+ gap: 12px !important;
293
+ z-index: 100;
294
+ }
295
+ .lp-editor-root .lp-editor-title {
296
+ margin-right: auto;
297
+ }
298
+ .lp-editor-root .lp-appearance-switcher {
299
+ display: inline-flex;
300
+ align-items: center;
301
+ background: #2a2a2a;
302
+ border: 1px solid #444;
303
+ border-radius: 999px;
304
+ padding: 3px;
305
+ gap: 3px;
306
+ }
307
+ .lp-editor-root .lp-appearance-btn {
308
+ display: inline-flex;
309
+ align-items: center;
310
+ gap: 5px;
311
+ background: transparent;
312
+ color: #aaa;
313
+ border: none;
314
+ border-radius: 999px;
315
+ padding: 5px 10px;
316
+ font-size: 13px;
317
+ cursor: pointer;
318
+ transition: background 0.15s, color 0.15s;
319
+ }
320
+ .lp-editor-root .lp-appearance-btn:hover {
321
+ color: #e5e5e5;
322
+ }
323
+ .lp-editor-root .lp-appearance-active {
324
+ background: #3a3a3a;
325
+ color: #fff;
326
+ font-weight: 500;
327
+ }
328
+ .lp-editor-root .lp-editor-btn {
329
+ display: inline-flex;
330
+ align-items: center;
331
+ gap: 6px;
332
+ background: #2a2a2a;
333
+ color: #e5e5e5;
334
+ border: 1px solid #444;
335
+ border-radius: 8px;
336
+ padding: 7px 12px;
337
+ font-size: 13px;
338
+ line-height: 1.4;
339
+ cursor: pointer;
340
+ transition: background 0.15s, border-color 0.15s, box-shadow 0.15s;
341
+ }
342
+ .lp-editor-root .lp-editor-btn:hover:not(:disabled) {
343
+ background: #333;
344
+ border-color: #555;
345
+ }
346
+ .lp-editor-root .lp-editor-btn:disabled {
347
+ opacity: 0.5;
348
+ cursor: not-allowed;
349
+ }
350
+ .lp-editor-root .lp-editor-btn-primary {
351
+ background: #34d399 !important;
352
+ border-color: #34d399 !important;
353
+ color: #111 !important;
354
+ font-weight: 600;
355
+ }
356
+ .lp-editor-root .lp-editor-btn-primary:hover:not(:disabled) {
357
+ background: #10b981 !important;
358
+ border-color: #10b981 !important;
359
+ }
360
+ .lp-editor-root .lp-editor-select {
361
+ background: #2a2a2a;
362
+ color: #e5e5e5;
363
+ border: 1px solid #444;
364
+ border-radius: 6px;
365
+ padding: 6px 10px;
366
+ font-size: 13px;
367
+ outline: none;
368
+ max-width: 120px;
369
+ }
370
+ .lp-editor-root .lp-editor-select:focus {
371
+ border-color: #5b8cff;
372
+ }
373
+ .lp-editor-export {
374
+ position: relative;
375
+ }
376
+ .lp-editor-export-toggle {
377
+ display: inline-flex;
378
+ align-items: center;
379
+ gap: 6px;
380
+ }
381
+ .lp-editor-caret {
382
+ font-size: 10px;
383
+ line-height: 1;
384
+ transform: translateY(1px);
385
+ }
386
+ .lp-editor-export-menu {
387
+ position: absolute;
388
+ top: calc(100% + 6px);
389
+ right: 0;
390
+ min-width: 220px;
391
+ background: #2a2a2a;
392
+ border: 1px solid #444;
393
+ border-radius: 8px;
394
+ padding: 6px;
395
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
396
+ z-index: 1000;
397
+ display: flex;
398
+ flex-direction: column;
399
+ gap: 2px;
400
+ }
401
+ .lp-editor-export-menu[hidden] {
402
+ display: none !important;
403
+ }
404
+ .lp-editor-export-item {
405
+ display: flex;
406
+ align-items: center;
407
+ gap: 10px;
408
+ width: 100%;
409
+ padding: 8px 10px;
410
+ background: transparent;
411
+ border: none;
412
+ border-radius: 6px;
413
+ color: #e5e5e5;
414
+ font-size: 14px;
415
+ cursor: pointer;
416
+ text-align: left;
417
+ }
418
+ .lp-editor-export-item:hover {
419
+ background: #3a3a3a;
420
+ }
421
+ .lp-editor-export-icon {
422
+ width: 20px;
423
+ text-align: center;
424
+ color: #aaa;
425
+ font-size: 14px;
426
+ }
427
+ .lp-editor-export-label {
428
+ flex: 1;
429
+ }
430
+ .lp-editor-export-tag {
431
+ font-size: 11px;
432
+ color: #999;
433
+ background: #3a3a3a;
434
+ padding: 2px 6px;
435
+ border-radius: 4px;
436
+ }
437
+ .lp-editor-workspace {
438
+ display: flex;
439
+ flex: 1;
440
+ min-height: 0;
441
+ }
442
+ .lp-editor-left-panel {
443
+ width: 180px;
444
+ flex: none;
445
+ background: #1e1e1e;
446
+ border-right: 1px solid #333;
447
+ overflow-y: auto;
448
+ padding: 12px;
449
+ position: relative;
450
+ }
451
+ .lp-editor-right-panel {
452
+ width: 400px;
453
+ flex: none;
454
+ background: #1e1e1e;
455
+ border-left: 1px solid #333;
456
+ overflow-y: auto;
457
+ padding: 16px;
458
+ }
459
+ .lp-editor-stage {
460
+ flex: 1;
461
+ display: flex;
462
+ align-items: center;
463
+ justify-content: center;
464
+ overflow: hidden;
465
+ position: relative;
466
+ background-color: #1a1a1a;
467
+ background-image: radial-gradient(circle, rgba(255,255,255,0.12) 1.5px, transparent 1.5px);
468
+ background-size: 28px 28px;
469
+ background-position: center center;
470
+ }
471
+ .lp-editor-stage-scaler {
472
+ transform-origin: center center;
473
+ transition: transform 0.2s ease;
474
+ position: relative;
475
+ }
476
+ .lp-editor-page-counter {
477
+ position: absolute;
478
+ bottom: -32px;
479
+ left: 50%;
480
+ transform: translateX(-50%);
481
+ color: #888;
482
+ font-size: 13px;
483
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
484
+ }
485
+ .lp-editor-thumbnails {
486
+ display: flex;
487
+ flex-direction: column;
488
+ gap: 10px;
489
+ }
490
+ .lp-thumbnail {
491
+ width: 100%;
492
+ aspect-ratio: 16 / 9;
493
+ border: 2px solid transparent;
494
+ border-radius: 6px;
495
+ background: #2a2a2a;
496
+ cursor: grab;
497
+ display: flex;
498
+ flex-direction: column;
499
+ justify-content: center;
500
+ padding: 10px;
501
+ text-align: left;
502
+ color: #bbb;
503
+ transition: border-color 0.15s, background 0.15s, opacity 0.15s;
504
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
505
+ position: relative;
506
+ user-select: none;
507
+ -webkit-user-select: none;
508
+ outline: none;
509
+ content-visibility: auto;
510
+ contain-intrinsic-size: auto 180px;
511
+ }
512
+ .lp-thumbnail:hover {
513
+ background: #333;
514
+ }
515
+ .lp-thumbnail:focus-visible {
516
+ border-color: #5b8cff;
517
+ }
518
+ .lp-thumbnail.active {
519
+ border-color: #3b82f6;
520
+ background: #26354f;
521
+ color: #fff;
522
+ }
523
+ .lp-thumbnail.dragging,
524
+ .lp-thumbnail:active {
525
+ cursor: grabbing;
526
+ }
527
+ .lp-thumbnail.dragging {
528
+ opacity: 0.45;
529
+ border: 2px dashed #3b82f6;
530
+ background: #1f2937;
531
+ }
532
+ .lp-thumbnail.drag-over {
533
+ border-color: #10b981;
534
+ background: #1f3d32;
535
+ }
536
+ .lp-thumbnail-index {
537
+ font-size: 11px;
538
+ color: #888;
539
+ margin-bottom: 4px;
540
+ }
541
+ .lp-thumbnail-title {
542
+ font-size: 13px;
543
+ font-weight: 500;
544
+ line-height: 1.3;
545
+ overflow: hidden;
546
+ text-overflow: ellipsis;
547
+ display: -webkit-box;
548
+ -webkit-line-clamp: 2;
549
+ -webkit-box-orient: vertical;
550
+ }
551
+ .lp-thumbnail-layout {
552
+ font-size: 11px;
553
+ color: #666;
554
+ margin-top: 4px;
555
+ }
556
+ .lp-thumbnail-drag-handle {
557
+ position: absolute;
558
+ top: 6px;
559
+ left: 6px;
560
+ width: 20px;
561
+ height: 24px;
562
+ display: flex;
563
+ flex-direction: column;
564
+ align-items: center;
565
+ justify-content: center;
566
+ gap: 2px;
567
+ opacity: 0.45;
568
+ z-index: 4;
569
+ color: #888;
570
+ transition: opacity 0.15s ease, color 0.15s ease, background 0.15s ease;
571
+ line-height: 1;
572
+ font-size: 10px;
573
+ user-select: none;
574
+ -webkit-user-select: none;
575
+ pointer-events: none;
576
+ border-radius: 4px;
577
+ padding: 2px;
578
+ }
579
+ .lp-thumbnail:hover .lp-thumbnail-drag-handle,
580
+ .lp-thumbnail-drag-handle:hover {
581
+ opacity: 0.9;
582
+ color: #bbb;
583
+ background: rgba(255, 255, 255, 0.08);
584
+ }
585
+ .lp-thumbnail.dragging .lp-thumbnail-drag-handle {
586
+ opacity: 1;
587
+ color: #fff;
588
+ background: rgba(255, 255, 255, 0.15);
589
+ }
590
+ .lp-thumbnail-drop-indicator {
591
+ position: absolute;
592
+ left: 0;
593
+ right: 0;
594
+ height: 3px;
595
+ background: #3b82f6;
596
+ border-radius: 2px;
597
+ pointer-events: none;
598
+ z-index: 10;
599
+ opacity: 0;
600
+ transition: opacity 0.1s ease;
601
+ box-shadow: 0 0 8px rgba(59, 130, 246, 0.6);
602
+ }
603
+ .lp-thumbnail-drop-indicator.visible {
604
+ opacity: 1;
605
+ }
606
+ .lp-delete-confirm-toast {
607
+ position: fixed;
608
+ z-index: 1000;
609
+ width: 180px;
610
+ background: #262626;
611
+ border: 1px solid #444;
612
+ border-radius: 8px;
613
+ padding: 12px;
614
+ box-shadow: 0 8px 24px rgba(0,0,0,0.35);
615
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
616
+ transition: opacity 0.15s ease, transform 0.15s ease;
617
+ margin: 0;
618
+ }
619
+ .lp-delete-confirm-toast[hidden] {
620
+ display: none;
621
+ }
622
+ .lp-delete-confirm-text {
623
+ font-size: 13px;
624
+ color: #e5e5e5;
625
+ line-height: 1.4;
626
+ margin-bottom: 10px;
627
+ }
628
+ .lp-delete-confirm-actions {
629
+ display: flex;
630
+ gap: 8px;
631
+ justify-content: flex-end;
632
+ }
633
+ .lp-delete-confirm-cancel,
634
+ .lp-delete-confirm-confirm {
635
+ padding: 5px 12px;
636
+ border-radius: 6px;
637
+ font-size: 13px;
638
+ cursor: pointer;
639
+ border: 1px solid #555;
640
+ background: #333;
641
+ color: #e5e5e5;
642
+ transition: background 0.15s, border-color 0.15s;
643
+ }
644
+ .lp-delete-confirm-cancel:hover {
645
+ background: #3a3a3a;
646
+ border-color: #666;
647
+ }
648
+ .lp-delete-confirm-confirm {
649
+ background: #dc2626;
650
+ border-color: #dc2626;
651
+ color: #fff;
652
+ }
653
+ .lp-delete-confirm-confirm:hover {
654
+ background: #b91c1c;
655
+ border-color: #b91c1c;
656
+ }
657
+ .lp-property-header {
658
+ font-size: 14px;
659
+ font-weight: 600;
660
+ margin-bottom: 12px;
661
+ color: #fff;
662
+ }
663
+ .lp-property-empty {
664
+ color: #888;
665
+ font-size: 13px;
666
+ line-height: 1.5;
667
+ }
668
+ .lp-property-group {
669
+ margin-bottom: 16px;
670
+ }
671
+ .lp-property-label {
672
+ font-size: 12px;
673
+ color: #999;
674
+ margin-bottom: 6px;
675
+ display: block;
676
+ }
677
+ .lp-property-input,
678
+ .lp-property-textarea {
679
+ width: 100%;
680
+ background: #2a2a2a;
681
+ border: 1px solid #444;
682
+ border-radius: 4px;
683
+ color: #e5e5e5;
684
+ padding: 8px 10px;
685
+ font-size: 13px;
686
+ font-family: inherit;
687
+ }
688
+ .lp-property-input:focus,
689
+ .lp-property-textarea:focus {
690
+ outline: none;
691
+ border-color: #3b82f6;
692
+ }
693
+ .lp-property-textarea {
694
+ min-height: 120px;
695
+ resize: vertical;
696
+ }
697
+ .lp-property-section {
698
+ margin-bottom: 18px;
699
+ padding-bottom: 14px;
700
+ border-bottom: 1px solid #333;
701
+ }
702
+ .lp-property-section:last-child {
703
+ border-bottom: none;
704
+ }
705
+ .lp-property-section-title {
706
+ font-size: 12px;
707
+ font-weight: 600;
708
+ color: #fff;
709
+ margin-bottom: 10px;
710
+ text-transform: uppercase;
711
+ letter-spacing: 0.05em;
712
+ }
713
+ .lp-property-section-header {
714
+ display: flex;
715
+ align-items: center;
716
+ justify-content: space-between;
717
+ margin-bottom: 10px;
718
+ }
719
+ .lp-property-section-header .lp-property-section-title {
720
+ margin-bottom: 0;
721
+ }
722
+ .lp-property-help {
723
+ font-size: 12px;
724
+ color: #888;
725
+ margin-bottom: 10px;
726
+ line-height: 1.4;
727
+ }
728
+ .lp-property-field {
729
+ margin-bottom: 12px;
730
+ }
731
+ .lp-property-field:last-child {
732
+ margin-bottom: 0;
733
+ }
734
+ .lp-property-input,
735
+ .lp-property-textarea {
736
+ width: 100%;
737
+ background: #2a2a2a;
738
+ border: 1px solid #444;
739
+ border-radius: 6px;
740
+ color: #e5e5e5;
741
+ padding: 8px 10px;
742
+ font-size: 13px;
743
+ font-family: inherit;
744
+ }
745
+ .lp-property-input:focus,
746
+ .lp-property-textarea:focus {
747
+ outline: none;
748
+ border-color: #3b82f6;
749
+ }
750
+ .lp-property-textarea {
751
+ min-height: 80px;
752
+ resize: vertical;
753
+ }
754
+ .lp-property-toggle {
755
+ display: flex;
756
+ align-items: center;
757
+ justify-content: space-between;
758
+ cursor: pointer;
759
+ }
760
+ .lp-property-toggle-track {
761
+ width: 46px;
762
+ height: 24px;
763
+ background: #444;
764
+ border-radius: 12px;
765
+ position: relative;
766
+ transition: background 0.25s ease;
767
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.25);
768
+ }
769
+ .lp-property-toggle input:checked + .lp-property-toggle-track {
770
+ background: #34d399;
771
+ }
772
+ .lp-property-toggle-thumb {
773
+ position: absolute;
774
+ top: 2px;
775
+ left: 2px;
776
+ width: 20px;
777
+ height: 20px;
778
+ background: #fff;
779
+ border-radius: 50%;
780
+ transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
781
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
782
+ }
783
+ .lp-property-toggle input:checked + .lp-property-toggle-track .lp-property-toggle-thumb {
784
+ transform: translateX(22px);
785
+ }
786
+ .lp-property-toggle input {
787
+ position: absolute;
788
+ opacity: 0;
789
+ width: 0;
790
+ height: 0;
791
+ }
792
+ .lp-property-segmented {
793
+ display: flex;
794
+ background: #2a2a2a;
795
+ border: 1px solid #444;
796
+ border-radius: 6px;
797
+ overflow: hidden;
798
+ }
799
+ .lp-property-segmented button {
800
+ flex: 1;
801
+ background: transparent;
802
+ border: none;
803
+ border-right: 1px solid #444;
804
+ color: #bbb;
805
+ padding: 6px 0;
806
+ font-size: 12px;
807
+ cursor: pointer;
808
+ }
809
+ .lp-property-segmented button:last-child {
810
+ border-right: none;
811
+ }
812
+ .lp-property-segmented button.active {
813
+ background: #3b82f6;
814
+ color: #fff;
815
+ }
816
+ .lp-property-color-grid {
817
+ display: grid;
818
+ grid-template: repeat(5, 1fr);
819
+ gap: 8px;
820
+ }
821
+ .lp-property-color-btn {
822
+ width: 100%;
823
+ aspect-ratio: 1;
824
+ border-radius: 50%;
825
+ border: 2px solid transparent;
826
+ cursor: pointer;
827
+ }
828
+ .lp-property-color-btn.active {
829
+ border-color: #fff;
830
+ }
831
+ .lp-property-range {
832
+ width: 100%;
833
+ }
834
+ .lp-property-slider-wrap {
835
+ margin-bottom: 16px;
836
+ }
837
+ .lp-property-slider-label {
838
+ font-size: 12px;
839
+ color: #bbb;
840
+ }
841
+ .lp-property-slider-value {
842
+ font-size: 13px;
843
+ font-weight: 700;
844
+ color: #fff;
845
+ min-width: 26px;
846
+ text-align: center;
847
+ padding: 2px 8px;
848
+ background: linear-gradient(135deg, rgba(91,155,213,0.9), rgba(139,92,246,0.9));
849
+ border-radius: 999px;
850
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
851
+ }
852
+ .lp-property-slider-ruler {
853
+ position: relative;
854
+ padding: 18px 18px 10px;
855
+ background: rgba(255, 255, 255, 0.04);
856
+ border: 1px solid rgba(255, 255, 255, 0.08);
857
+ border-radius: 14px;
858
+ cursor: pointer;
859
+ transition: background 0.2s ease, border-color 0.2s ease;
860
+ }
861
+ .lp-property-slider-ruler:hover {
862
+ background: rgba(255, 255, 255, 0.07);
863
+ border-color: rgba(255, 255, 255, 0.14);
864
+ }
865
+ .lp-property-slider-ruler::before {
866
+ content: '';
867
+ position: absolute;
868
+ top: 22px;
869
+ left: 18px;
870
+ right: 18px;
871
+ height: 2px;
872
+ background: rgba(255, 255, 255, 0.12);
873
+ border-radius: 1px;
874
+ pointer-events: none;
875
+ }
876
+ .lp-property-slider {
877
+ width: 100%;
878
+ -webkit-appearance: none;
879
+ appearance: none;
880
+ height: 8px;
881
+ background: rgba(255, 255, 255, 0.14);
882
+ border-radius: 4px;
883
+ outline: none;
884
+ display: block;
885
+ margin: 0;
886
+ cursor: pointer;
887
+ transition: box-shadow 0.2s ease;
888
+ }
889
+ .lp-property-slider:hover {
890
+ box-shadow: 0 0 0 4px rgba(91, 155, 213, 0.12);
891
+ }
892
+ .lp-property-slider::-webkit-slider-thumb {
893
+ -webkit-appearance: none;
894
+ appearance: none;
895
+ width: 24px;
896
+ height: 24px;
897
+ background: #fff;
898
+ border-radius: 50%;
899
+ cursor: grab;
900
+ border: 4px solid #5b9bd5;
901
+ box-shadow: 0 0 0 4px rgba(91, 155, 213, 0.2), 0 4px 12px rgba(0, 0, 0, 0.35);
902
+ margin-top: -8px;
903
+ transition: transform 0.15s ease, box-shadow 0.2s ease;
904
+ }
905
+ .lp-property-slider::-webkit-slider-thumb:hover {
906
+ transform: scale(1.12);
907
+ box-shadow: 0 0 0 6px rgba(91, 155, 213, 0.28), 0 6px 16px rgba(0, 0, 0, 0.4);
908
+ }
909
+ .lp-property-slider:active::-webkit-slider-thumb {
910
+ cursor: grabbing;
911
+ transform: scale(1.05);
912
+ border-color: #8b5cf6;
913
+ }
914
+ .lp-property-slider::-webkit-slider-runnable-track {
915
+ height: 8px;
916
+ border-radius: 4px;
917
+ }
918
+ .lp-property-slider::-moz-range-thumb {
919
+ width: 24px;
920
+ height: 24px;
921
+ background: #fff;
922
+ border-radius: 50%;
923
+ cursor: grab;
924
+ border: 4px solid #5b9bd5;
925
+ box-shadow: 0 0 0 4px rgba(91, 155, 213, 0.2), 0 4px 12px rgba(0, 0, 0, 0.35);
926
+ transition: transform 0.15s ease, box-shadow 0.2s ease;
927
+ }
928
+ .lp-property-slider::-moz-range-thumb:hover {
929
+ transform: scale(1.12);
930
+ box-shadow: 0 0 0 6px rgba(91, 155, 213, 0.28), 0 6px 16px rgba(0, 0, 0, 0.4);
931
+ }
932
+ .lp-property-slider::-moz-range-progress {
933
+ background: #5b9bd5;
934
+ border-radius: 4px;
935
+ height: 8px;
936
+ }
937
+ .lp-add-slide-modal-overlay {
938
+ position: fixed;
939
+ inset: 0;
940
+ background: rgba(0,0,0,0.6);
941
+ z-index: 2000;
942
+ display: flex;
943
+ align-items: center;
944
+ justify-content: center;
945
+ opacity: 0;
946
+ pointer-events: none;
947
+ transition: opacity 0.2s ease;
948
+ }
949
+ .lp-add-slide-modal-overlay.active {
950
+ opacity: 1;
951
+ pointer-events: auto;
952
+ }
953
+ .lp-add-slide-modal {
954
+ width: 600px;
955
+ max-width: 90vw;
956
+ max-height: 80vh;
957
+ background: #1e1e1e;
958
+ border: 1px solid #333;
959
+ border-radius: 12px;
960
+ overflow: hidden;
961
+ display: flex;
962
+ flex-direction: column;
963
+ box-shadow: 0 20px 60px rgba(0,0,0,0.5);
964
+ }
965
+ .lp-add-slide-modal-header {
966
+ display: flex;
967
+ align-items: center;
968
+ justify-content: space-between;
969
+ padding: 16px 20px;
970
+ border-bottom: 1px solid #333;
971
+ }
972
+ .lp-add-slide-modal-title {
973
+ font-size: 16px;
974
+ font-weight: 600;
975
+ color: #fff;
976
+ }
977
+ .lp-add-slide-modal-close {
978
+ background: transparent;
979
+ border: none;
980
+ color: #888;
981
+ font-size: 20px;
982
+ cursor: pointer;
983
+ }
984
+ .lp-add-slide-modal-close:hover {
985
+ color: #fff;
986
+ }
987
+ .lp-add-slide-modal-body {
988
+ padding: 16px 20px;
989
+ overflow-y: auto;
990
+ flex: 1;
991
+ }
992
+ .lp-add-slide-section-title {
993
+ font-size: 13px;
994
+ font-weight: 600;
995
+ color: #bbb;
996
+ margin: 16px 0 10px;
997
+ }
998
+ .lp-add-slide-section-title:first-child {
999
+ margin-top: 0;
1000
+ }
1001
+ .lp-add-slide-grid {
1002
+ display: grid;
1003
+ grid-template-columns: repeat(4, 1fr);
1004
+ gap: 10px;
1005
+ }
1006
+ .lp-add-slide-item {
1007
+ aspect-ratio: 16 / 9;
1008
+ background: #2a2a2a;
1009
+ border: 1px solid #444;
1010
+ border-radius: 6px;
1011
+ display: flex;
1012
+ flex-direction: column;
1013
+ align-items: center;
1014
+ justify-content: center;
1015
+ gap: 6px;
1016
+ cursor: pointer;
1017
+ transition: background 0.15s, border-color 0.15s;
1018
+ padding: 8px;
1019
+ text-align: center;
1020
+ }
1021
+ .lp-add-slide-item:hover {
1022
+ background: #333;
1023
+ border-color: #5b8cff;
1024
+ }
1025
+ .lp-add-slide-item-icon {
1026
+ font-size: 24px;
1027
+ color: #888;
1028
+ }
1029
+ .lp-add-slide-item-label {
1030
+ font-size: 12px;
1031
+ color: #bbb;
1032
+ }
1033
+ .lp-filmstrip-v1-track {
1034
+ display: flex;
1035
+ flex-direction: column;
1036
+ gap: 10px;
1037
+ padding: 10px;
1038
+ overflow-y: auto;
1039
+ max-height: 100%;
1040
+ }
1041
+ .lp-filmstrip-v1-track.lp-custom-scrollbar::-webkit-scrollbar {
1042
+ width: 8px;
1043
+ height: 8px;
1044
+ }
1045
+ .lp-filmstrip-v1-track.lp-custom-scrollbar::-webkit-scrollbar-track {
1046
+ background: rgba(0, 0, 0, 0.08);
1047
+ border-radius: 4px;
1048
+ }
1049
+ .lp-filmstrip-v1-track.lp-custom-scrollbar::-webkit-scrollbar-thumb {
1050
+ background: rgba(0, 0, 0, 0.35);
1051
+ border-radius: 4px;
1052
+ }
1053
+ .lp-filmstrip-v1-track.lp-custom-scrollbar::-webkit-scrollbar-thumb:hover {
1054
+ background: rgba(0, 0, 0, 0.55);
1055
+ }
1056
+ .lp-filmstrip-v1-track.lp-custom-scrollbar {
1057
+ scrollbar-width: thin;
1058
+ scrollbar-color: rgba(0, 0, 0, 0.35) rgba(0, 0, 0, 0.08);
1059
+ }
1060
+ </style>
1061
+ </head>
1062
+ <body class="lp-editor-body">
1063
+ ${bodyMarkup}
1064
+ </body>
1065
+ </html>`;
1066
+ return { html, assets: [] };
1067
+ }
1068
+ //# sourceMappingURL=render-editor-data.js.map