tinymce-plugin-multipreview 1.0.0 → 1.0.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.
@@ -0,0 +1 @@
1
+ "use strict";const e=(t,o)=>{const c=t.__vccOpts||t;for(const[r,s]of o)c[r]=s;return c};exports._export_sfc=e;
@@ -0,0 +1,9 @@
1
+ const s = (t, r) => {
2
+ const o = t.__vccOpts || t;
3
+ for (const [c, e] of r)
4
+ o[c] = e;
5
+ return o;
6
+ };
7
+ export {
8
+ s as _
9
+ };
@@ -0,0 +1,420 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c="multipreview",n={mobile:{label:"手机",icon:`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
2
+ <rect x="5" y="2" width="14" height="20" rx="2" ry="2"/>
3
+ <line x1="12" y1="18" x2="12.01" y2="18"/>
4
+ </svg>`,width:375,height:812,scale:.75},tablet:{label:"平板",icon:`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
5
+ <rect x="4" y="2" width="16" height="20" rx="2" ry="2"/>
6
+ <line x1="12" y1="18" x2="12.01" y2="18"/>
7
+ </svg>`,width:768,height:1024,scale:.65},desktop:{label:"电脑",icon:`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
8
+ <rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
9
+ <line x1="8" y1="21" x2="16" y2="21"/>
10
+ <line x1="12" y1="17" x2="12" y2="21"/>
11
+ </svg>`,width:1280,height:800,scale:.55}};function d(i,e){const t=i.getContent();return`<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8">
12
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
13
+ <title>预览</title>${`
14
+ <style>
15
+ * { box-sizing: border-box; }
16
+ body {
17
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
18
+ font-size: 16px;
19
+ line-height: 1.7;
20
+ color: #333;
21
+ margin: 0;
22
+ padding: 20px;
23
+ word-wrap: break-word;
24
+ overflow-wrap: break-word;
25
+ }
26
+ img { max-width: 100%; height: auto; }
27
+ table { border-collapse: collapse; width: 100%; }
28
+ td, th { border: 1px solid #ddd; padding: 8px; }
29
+ pre { overflow-x: auto; background: #f5f5f5; padding: 12px; border-radius: 4px; }
30
+ code { background: #f5f5f5; padding: 2px 4px; border-radius: 3px; font-size: 0.9em; }
31
+ blockquote {
32
+ border-left: 4px solid #ddd;
33
+ margin: 0;
34
+ padding-left: 16px;
35
+ color: #666;
36
+ }
37
+ h1,h2,h3,h4,h5,h6 { line-height: 1.3; margin-top: 1.5em; margin-bottom: 0.5em; }
38
+ p { margin: 0.8em 0; }
39
+ a { color: #0066cc; }
40
+ ul, ol { padding-left: 1.5em; }
41
+ ${e||""}
42
+ </style>
43
+ `}</head><body>${t}</body></html>`}function h(){return`
44
+ <div class="tpm-overlay" id="tpm-overlay">
45
+ <div class="tpm-modal">
46
+ <!-- 顶部工具栏 -->
47
+ <div class="tpm-toolbar">
48
+ <div class="tpm-toolbar-left">
49
+ <div class="tpm-logo">
50
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
51
+ <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
52
+ <circle cx="12" cy="12" r="3"/>
53
+ </svg>
54
+ <span>内容预览</span>
55
+ </div>
56
+ </div>
57
+ <div class="tpm-device-tabs">
58
+ ${Object.entries(n).map(([e,t])=>`
59
+ <button class="tpm-device-btn ${e==="mobile"?"active":""}" data-device="${e}" title="${t.label}">
60
+ ${t.icon}
61
+ <span>${t.label}</span>
62
+ </button>
63
+ `).join("")}
64
+ </div>
65
+ <div class="tpm-toolbar-right">
66
+ <button class="tpm-btn tpm-btn-rotate" id="tpm-rotate" title="旋转屏幕">
67
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
68
+ <polyline points="23 4 23 10 17 10"/>
69
+ <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/>
70
+ </svg>
71
+ </button>
72
+ <button class="tpm-btn tpm-btn-close" id="tpm-close" title="关闭">
73
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
74
+ <line x1="18" y1="6" x2="6" y2="18"/>
75
+ <line x1="6" y1="6" x2="18" y2="18"/>
76
+ </svg>
77
+ </button>
78
+ </div>
79
+ </div>
80
+
81
+ <!-- 预览区域 -->
82
+ <div class="tpm-stage" id="tpm-stage">
83
+ <div class="tpm-device-wrapper" id="tpm-device-wrapper">
84
+ <div class="tpm-device-frame" id="tpm-device-frame">
85
+ <div class="tpm-device-notch" id="tpm-device-notch">
86
+ <div class="tpm-notch-inner"></div>
87
+ </div>
88
+ <div class="tpm-device-screen">
89
+ <iframe class="tpm-iframe" id="tpm-iframe" sandbox="allow-same-origin allow-scripts"></iframe>
90
+ </div>
91
+ <div class="tpm-device-home" id="tpm-device-home">
92
+ <div class="tpm-home-bar"></div>
93
+ </div>
94
+ </div>
95
+ </div>
96
+ </div>
97
+
98
+ <!-- 底部信息栏 -->
99
+ <div class="tpm-footer">
100
+ <span class="tpm-device-info" id="tpm-device-info">375 × 812</span>
101
+ <span class="tpm-separator">·</span>
102
+ <span class="tpm-device-label" id="tpm-device-label">手机预览</span>
103
+ <span class="tpm-hint">横屏模式下旋转设备以获得更好体验</span>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ `}const g=`
108
+ .tpm-overlay {
109
+ position: fixed;
110
+ inset: 0;
111
+ background: rgba(8, 8, 20, 0.85);
112
+ backdrop-filter: blur(12px);
113
+ -webkit-backdrop-filter: blur(12px);
114
+ z-index: 999999;
115
+ display: flex;
116
+ align-items: center;
117
+ justify-content: center;
118
+ animation: tpm-fade-in 0.25s ease;
119
+ }
120
+ @keyframes tpm-fade-in {
121
+ from { opacity: 0; }
122
+ to { opacity: 1; }
123
+ }
124
+ .tpm-modal {
125
+ width: 100%;
126
+ height: 100%;
127
+ display: flex;
128
+ flex-direction: column;
129
+ overflow: hidden;
130
+ }
131
+
132
+ /* 工具栏 */
133
+ .tpm-toolbar {
134
+ display: flex;
135
+ align-items: center;
136
+ justify-content: space-between;
137
+ padding: 0 24px;
138
+ height: 60px;
139
+ background: rgba(255,255,255,0.04);
140
+ border-bottom: 1px solid rgba(255,255,255,0.08);
141
+ flex-shrink: 0;
142
+ gap: 16px;
143
+ }
144
+ .tpm-toolbar-left, .tpm-toolbar-right {
145
+ display: flex;
146
+ align-items: center;
147
+ gap: 8px;
148
+ min-width: 120px;
149
+ }
150
+ .tpm-toolbar-right { justify-content: flex-end; }
151
+ .tpm-logo {
152
+ display: flex;
153
+ align-items: center;
154
+ gap: 8px;
155
+ color: rgba(255,255,255,0.9);
156
+ font-size: 15px;
157
+ font-weight: 600;
158
+ letter-spacing: 0.02em;
159
+ }
160
+ .tpm-logo svg {
161
+ width: 20px;
162
+ height: 20px;
163
+ color: #6ee7f7;
164
+ }
165
+ .tpm-device-tabs {
166
+ display: flex;
167
+ align-items: center;
168
+ gap: 4px;
169
+ background: rgba(255,255,255,0.06);
170
+ border-radius: 10px;
171
+ padding: 4px;
172
+ }
173
+ .tpm-device-btn {
174
+ display: flex;
175
+ align-items: center;
176
+ gap: 6px;
177
+ padding: 6px 14px;
178
+ border: none;
179
+ background: transparent;
180
+ color: rgba(255,255,255,0.5);
181
+ border-radius: 7px;
182
+ cursor: pointer;
183
+ font-size: 13px;
184
+ font-weight: 500;
185
+ transition: all 0.2s ease;
186
+ white-space: nowrap;
187
+ }
188
+ .tpm-device-btn svg {
189
+ width: 16px;
190
+ height: 16px;
191
+ flex-shrink: 0;
192
+ }
193
+ .tpm-device-btn:hover {
194
+ color: rgba(255,255,255,0.8);
195
+ background: rgba(255,255,255,0.08);
196
+ }
197
+ .tpm-device-btn.active {
198
+ background: rgba(110, 231, 247, 0.15);
199
+ color: #6ee7f7;
200
+ }
201
+ .tpm-btn {
202
+ display: flex;
203
+ align-items: center;
204
+ justify-content: center;
205
+ width: 36px;
206
+ height: 36px;
207
+ border: none;
208
+ background: rgba(255,255,255,0.06);
209
+ color: rgba(255,255,255,0.6);
210
+ border-radius: 8px;
211
+ cursor: pointer;
212
+ transition: all 0.2s ease;
213
+ }
214
+ .tpm-btn svg { width: 18px; height: 18px; }
215
+ .tpm-btn:hover {
216
+ background: rgba(255,255,255,0.12);
217
+ color: rgba(255,255,255,0.9);
218
+ }
219
+ .tpm-btn-close:hover { background: rgba(255, 80, 80, 0.2); color: #ff6b6b; }
220
+
221
+ /* 预览舞台 */
222
+ .tpm-stage {
223
+ flex: 1;
224
+ display: flex;
225
+ align-items: center;
226
+ justify-content: center;
227
+ overflow: hidden;
228
+ padding: 30px 20px;
229
+ position: relative;
230
+ }
231
+ .tpm-stage::before {
232
+ content: '';
233
+ position: absolute;
234
+ inset: 0;
235
+ background: radial-gradient(ellipse at 50% 50%, rgba(110, 231, 247, 0.03) 0%, transparent 70%);
236
+ pointer-events: none;
237
+ }
238
+ .tpm-device-wrapper {
239
+ display: flex;
240
+ align-items: center;
241
+ justify-content: center;
242
+ transition: all 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
243
+ transform-origin: center center;
244
+ }
245
+
246
+ /* 设备外壳 */
247
+ .tpm-device-frame {
248
+ position: relative;
249
+ border-radius: 40px;
250
+ background: linear-gradient(160deg, #2a2a3e 0%, #1a1a2e 50%, #12121f 100%);
251
+ box-shadow:
252
+ 0 0 0 1px rgba(255,255,255,0.12),
253
+ 0 0 0 2px rgba(0,0,0,0.8),
254
+ 0 30px 80px rgba(0,0,0,0.6),
255
+ inset 0 1px 0 rgba(255,255,255,0.1),
256
+ 0 0 60px rgba(110, 231, 247, 0.06);
257
+ transition: all 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
258
+ overflow: hidden;
259
+ }
260
+ .tpm-device-frame::before {
261
+ content: '';
262
+ position: absolute;
263
+ inset: 0;
264
+ border-radius: inherit;
265
+ background: linear-gradient(135deg, rgba(255,255,255,0.06) 0%, transparent 50%);
266
+ pointer-events: none;
267
+ z-index: 2;
268
+ }
269
+
270
+ /* 刘海 */
271
+ .tpm-device-notch {
272
+ position: absolute;
273
+ top: 0;
274
+ left: 50%;
275
+ transform: translateX(-50%);
276
+ width: 120px;
277
+ height: 30px;
278
+ background: #0a0a14;
279
+ border-radius: 0 0 20px 20px;
280
+ z-index: 10;
281
+ display: flex;
282
+ align-items: center;
283
+ justify-content: center;
284
+ transition: all 0.3s ease;
285
+ }
286
+ .tpm-notch-inner {
287
+ width: 60px;
288
+ height: 6px;
289
+ background: #1a1a2e;
290
+ border-radius: 3px;
291
+ }
292
+
293
+ /* 屏幕 */
294
+ .tpm-device-screen {
295
+ position: absolute;
296
+ inset: 12px;
297
+ border-radius: 28px;
298
+ overflow: hidden;
299
+ background: #fff;
300
+ }
301
+ .tpm-iframe {
302
+ width: 100%;
303
+ height: 100%;
304
+ border: none;
305
+ display: block;
306
+ }
307
+
308
+ /* Home 条 */
309
+ .tpm-device-home {
310
+ position: absolute;
311
+ bottom: 8px;
312
+ left: 50%;
313
+ transform: translateX(-50%);
314
+ z-index: 10;
315
+ display: flex;
316
+ align-items: center;
317
+ justify-content: center;
318
+ transition: all 0.3s ease;
319
+ }
320
+ .tpm-home-bar {
321
+ width: 100px;
322
+ height: 4px;
323
+ background: rgba(255,255,255,0.35);
324
+ border-radius: 2px;
325
+ }
326
+
327
+ /* 平板样式 */
328
+ .tpm-device-frame.tablet {
329
+ border-radius: 24px;
330
+ }
331
+ .tpm-device-frame.tablet .tpm-device-notch {
332
+ width: 80px;
333
+ height: 20px;
334
+ border-radius: 0 0 12px 12px;
335
+ }
336
+ .tpm-device-frame.tablet .tpm-notch-inner {
337
+ width: 40px;
338
+ height: 5px;
339
+ }
340
+
341
+ /* PC 样式 */
342
+ .tpm-device-frame.desktop {
343
+ border-radius: 12px 12px 0 0;
344
+ }
345
+ .tpm-device-frame.desktop .tpm-device-notch { display: none; }
346
+ .tpm-device-frame.desktop .tpm-device-home { display: none; }
347
+ .tpm-device-frame.desktop .tpm-device-screen { inset: 32px 8px 8px; border-radius: 4px; }
348
+ .tpm-device-frame.desktop::after {
349
+ content: '';
350
+ position: absolute;
351
+ top: 0;
352
+ left: 0;
353
+ right: 0;
354
+ height: 32px;
355
+ background: linear-gradient(to bottom, #252538, #1e1e30);
356
+ display: flex;
357
+ align-items: center;
358
+ padding-left: 16px;
359
+ }
360
+ .tpm-desktop-bar {
361
+ position: absolute;
362
+ top: 0;
363
+ left: 0;
364
+ right: 0;
365
+ height: 32px;
366
+ background: linear-gradient(to bottom, #2a2a42, #1e1e32);
367
+ border-radius: 12px 12px 0 0;
368
+ display: flex;
369
+ align-items: center;
370
+ padding: 0 12px;
371
+ gap: 6px;
372
+ z-index: 5;
373
+ }
374
+ .tpm-desktop-dot {
375
+ width: 10px;
376
+ height: 10px;
377
+ border-radius: 50%;
378
+ }
379
+
380
+ /* 底部信息 */
381
+ .tpm-footer {
382
+ display: flex;
383
+ align-items: center;
384
+ justify-content: center;
385
+ gap: 8px;
386
+ height: 40px;
387
+ background: rgba(255,255,255,0.03);
388
+ border-top: 1px solid rgba(255,255,255,0.06);
389
+ flex-shrink: 0;
390
+ font-size: 12px;
391
+ color: rgba(255,255,255,0.3);
392
+ }
393
+ .tpm-device-info { color: rgba(110, 231, 247, 0.7); font-weight: 600; letter-spacing: 0.05em; }
394
+ .tpm-separator { color: rgba(255,255,255,0.15); }
395
+ .tpm-device-label { color: rgba(255,255,255,0.5); }
396
+ .tpm-hint { margin-left: 16px; font-size: 11px; opacity: 0.6; }
397
+
398
+ /* 旋转动画 */
399
+ .tpm-device-wrapper.rotating .tpm-device-frame {
400
+ animation: tpm-rotate-pulse 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
401
+ }
402
+ @keyframes tpm-rotate-pulse {
403
+ 0% { transform: scale(1); }
404
+ 50% { transform: scale(0.9) rotate(5deg); }
405
+ 100% { transform: scale(1); }
406
+ }
407
+
408
+ /* 设备切换动画 */
409
+ @keyframes tpm-device-in {
410
+ from { opacity: 0; transform: scale(0.85) translateY(20px); }
411
+ to { opacity: 1; transform: scale(1) translateY(0); }
412
+ }
413
+ .tpm-device-frame.entering {
414
+ animation: tpm-device-in 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
415
+ }
416
+ `;function b(){if(document.getElementById("tpm-styles"))return;const i=document.createElement("style");i.id="tpm-styles",i.textContent=g,document.head.appendChild(i)}class l{constructor(e,t={}){this.editor=e,this.options=t,this.currentDevice="mobile",this.isLandscape=!1,this.modal=null}open(){b();const e=document.createElement("div");e.innerHTML=h(),this.modal=e.firstElementChild,document.body.appendChild(this.modal),this._setupEvents(),this._switchDevice("mobile",!1),this._loadContent()}close(){this.modal&&(this.modal.style.animation="tpm-fade-in 0.2s ease reverse",setTimeout(()=>{var e;(e=this.modal)==null||e.remove(),this.modal=null},200))}_loadContent(){const e=this.modal.querySelector("#tpm-iframe"),t=d(this.editor,this.options.customStyles),r=new Blob([t],{type:"text/html;charset=utf-8"}),o=URL.createObjectURL(r);e.src=o,e.onload=()=>URL.revokeObjectURL(o)}_switchDevice(e,t=!0){var m;this.currentDevice=e,this.isLandscape=!1;const r=n[e],o=this.modal.querySelector("#tpm-device-frame");if(this.modal.querySelector("#tpm-device-wrapper"),o.className=`tpm-device-frame ${e}`,t&&(o.classList.add("entering"),setTimeout(()=>o.classList.remove("entering"),400)),e==="desktop"){if(!o.querySelector(".tpm-desktop-bar")){const a=document.createElement("div");a.className="tpm-desktop-bar",a.innerHTML=`
417
+ <div class="tpm-desktop-dot" style="background:#ff5f57"></div>
418
+ <div class="tpm-desktop-dot" style="background:#febc2e"></div>
419
+ <div class="tpm-desktop-dot" style="background:#28c840"></div>
420
+ `,o.prepend(a)}}else(m=o.querySelector(".tpm-desktop-bar"))==null||m.remove();this._applyDimensions(r.width,r.height,r.scale),this._updateInfo(r),this.modal.querySelectorAll(".tpm-device-btn").forEach(a=>{a.classList.toggle("active",a.dataset.device===e)});const p=this.modal.querySelector("#tpm-rotate");p.style.display=e==="desktop"?"none":"flex"}_applyDimensions(e,t,r){const o=this.modal.querySelector("#tpm-device-frame"),p=this.modal.querySelector("#tpm-device-wrapper");o.style.width=e+"px",o.style.height=t+"px",p.style.transform=`scale(${r})`}_rotate(){const e=n[this.currentDevice];this.isLandscape=!this.isLandscape;const t=this.modal.querySelector("#tpm-device-wrapper");t.classList.add("rotating"),setTimeout(()=>t.classList.remove("rotating"),500),this.isLandscape?(this._applyDimensions(e.height,e.width,e.scale*.85),this._updateInfo({...e,width:e.height,height:e.width,label:e.label+" (横屏)"})):(this._applyDimensions(e.width,e.height,e.scale),this._updateInfo(e))}_updateInfo(e){const t=this.modal.querySelector("#tpm-device-frame"),r=parseInt(t.style.width),o=parseInt(t.style.height);this.modal.querySelector("#tpm-device-info").textContent=`${r} × ${o}`,this.modal.querySelector("#tpm-device-label").textContent=e.label+" 预览"}_setupEvents(){this.modal.querySelector("#tpm-close").addEventListener("click",()=>this.close()),this.modal.addEventListener("click",e=>{e.target===this.modal&&this.close()}),this._keyHandler=e=>{e.key==="Escape"&&this.close()},document.addEventListener("keydown",this._keyHandler),this.modal.querySelectorAll(".tpm-device-btn").forEach(e=>{e.addEventListener("click",()=>this._switchDevice(e.dataset.device))}),this.modal.querySelector("#tpm-rotate").addEventListener("click",()=>this._rotate())}destroy(){document.removeEventListener("keydown",this._keyHandler),this.close()}}function s(i,e={}){return i.addCommand("mceMultiPreview",function(){new l(i,e).open()}),i.ui.registry.addButton("multipreview",{tooltip:"多端预览",icon:"preview",onAction:()=>i.execCommand("mceMultiPreview")}),i.ui.registry.addMenuItem("multipreview",{text:"多端预览",icon:"preview",onAction:()=>i.execCommand("mceMultiPreview")}),{getMetadata:()=>({name:"Multi-Device Preview Plugin",url:"https://github.com/your-org/tinymce-plugin-multipreview"})}}typeof window<"u"&&(typeof window.tinymce<"u"&&window.tinymce.PluginManager.add(c,function(i){const e=i.getParam("multipreview",{});return s(i,e)}),window.TinyMCEPreviewPlugin={PreviewController:l,DEVICES:n,getFullHtml:d,initPlugin:s});typeof module<"u"&&module.exports&&(module.exports={PreviewController:l,DEVICES:n,getFullHtml:d,initPlugin:s,PLUGIN_NAME:c});exports.DEVICES=n;exports.PLUGIN_NAME=c;exports.PreviewController=l;exports.getFullHtml=d;exports.initPlugin=s;