PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / device-mockup / frontend.js

frontend.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/device-mockup/frontend.js

222 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 'use strict';
3
4 var ASPECTS = { phone: 9 / 19.5, tablet: 4 / 3, laptop: 16 / 10, browser: 16 / 10 };
5
6 var FRAME_COLORS = {
7 'silver': '#d4d4d8',
8 'space-gray': '#374151',
9 'gold': '#d4a853',
10 'white': '#f9fafb',
11 'black': '#111827',
12 };
13
14 var PLACEHOLDER = 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="300" height="200"><rect width="300" height="200" fill="%23e5e7eb"/><text x="50%25" y="50%25" font-family="sans-serif" font-size="14" fill="%239ca3af" text-anchor="middle" dy=".3em">No Image</text></svg>';
15
16 function reducedMotion() {
17 return window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
18 }
19
20 function el(tag, attrs, children) {
21 var node = document.createElement(tag);
22 if (attrs) {
23 Object.keys(attrs).forEach(function (k) {
24 if (k === 'style' && typeof attrs[k] === 'object') {
25 Object.assign(node.style, attrs[k]);
26 } else {
27 node.setAttribute(k, attrs[k]);
28 }
29 });
30 }
31 if (children) {
32 (Array.isArray(children) ? children : [children]).forEach(function (c) {
33 if (c) node.appendChild(typeof c === 'string' ? document.createTextNode(c) : c);
34 });
35 }
36 return node;
37 }
38
39 function buildDevice(wrap) {
40 var cfg = {
41 device: wrap.dataset.device || 'phone',
42 frameColor: wrap.dataset.frameColor || 'silver',
43 frameCustom: wrap.dataset.frameCustom || '#d4d4d8',
44 maxWidth: parseInt(wrap.dataset.maxWidth, 10) || 380,
45 scale: parseFloat(wrap.dataset.scale) || 100,
46 tiltX: parseFloat(wrap.dataset.tiltX) || 0,
47 tiltY: parseFloat(wrap.dataset.tiltY) || 0,
48 shadow: wrap.dataset.shadow !== 'false',
49 shadowInt: parseInt(wrap.dataset.shadowInt, 10) || 30,
50 reflection: wrap.dataset.reflection === 'true',
51 hoverLift: wrap.dataset.hoverLift !== 'false',
52 scrollAnim: wrap.dataset.scrollAnim === 'true',
53 frameStroke: parseInt(wrap.dataset.frameStroke, 10) || 12,
54 screenRadius: parseInt(wrap.dataset.screenRadius, 10)|| 8,
55 outerRadius: parseInt(wrap.dataset.outerRadius, 10) || 40,
56 notch: wrap.dataset.notch !== 'false',
57 homeInd: wrap.dataset.homeInd !== 'false',
58 browserChrome:wrap.dataset.browserChrome !== 'false',
59 browserUrl: wrap.dataset.browserUrl || 'https://example.com',
60 imgUrl: wrap.dataset.imgUrl || PLACEHOLDER,
61 imgAlt: wrap.dataset.imgAlt || '',
62 align: wrap.dataset.align || 'center',
63 };
64
65 var frameColor = cfg.frameColor === 'custom' ? cfg.frameCustom : (FRAME_COLORS[cfg.frameColor] || '#d4d4d8');
66 var aspect = ASPECTS[cfg.device] || (9 / 19.5);
67 var sw = cfg.maxWidth;
68 var fs = cfg.frameStroke;
69 var or = cfg.outerRadius;
70 var sr = cfg.screenRadius;
71 var scale = cfg.scale / 100;
72
73 var shadowVal = cfg.shadow
74 ? '0 ' + Math.round(sw * 0.06) + 'px ' + Math.round(sw * 0.14) + 'px rgba(0,0,0,' + (cfg.shadowInt / 100) + ')'
75 : 'none';
76
77 var tform = '';
78 if (cfg.tiltX !== 0 || cfg.tiltY !== 0) {
79 tform = 'perspective(1200px) rotateX(' + cfg.tiltY + 'deg) rotateY(' + cfg.tiltX + 'deg)';
80 }
81 if (scale !== 1) tform += (tform ? ' ' : '') + 'scale(' + scale + ')';
82
83 wrap.style.textAlign = cfg.align === 'right' ? 'right' : cfg.align === 'center' ? 'center' : 'left';
84
85 var outer = el('div', { class: 'bkdv-device-outer' });
86 if (tform && !reducedMotion()) outer.style.transform = tform;
87
88 function makeImg() {
89 var img = el('img');
90 img.src = cfg.imgUrl;
91 img.alt = cfg.imgAlt;
92 img.style.cssText = 'position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;';
93 return img;
94 }
95
96 function makeReflection() {
97 var r = el('div');
98 r.style.cssText = 'position:absolute;inset:0;background:linear-gradient(135deg,rgba(255,255,255,0.2) 0%,transparent 55%);pointer-events:none;z-index:2;';
99 return r;
100 }
101
102 /* ── Phone / Tablet ── */
103 if (cfg.device === 'phone' || cfg.device === 'tablet') {
104 var device = el('div');
105 device.style.cssText = 'position:relative;width:' + sw + 'px;box-sizing:border-box;background:' + frameColor + ';border-radius:' + or + 'px;padding:' + fs + 'px;box-shadow:' + shadowVal + ';display:inline-block;';
106
107 var screen = el('div');
108 screen.style.cssText = 'position:relative;width:100%;padding-bottom:' + (100 / aspect) + '%;border-radius:' + sr + 'px;overflow:hidden;background:#000;';
109
110 screen.appendChild(makeImg());
111
112 if (cfg.reflection) screen.appendChild(makeReflection());
113
114 if (cfg.notch && cfg.device === 'phone') {
115 var notch = el('div', { class: 'bkdv-notch' });
116 notch.style.cssText = 'position:absolute;top:0;left:50%;transform:translateX(-50%);width:28%;height:20px;background:' + frameColor + ';border-bottom-left-radius:12px;border-bottom-right-radius:12px;z-index:3;';
117 screen.appendChild(notch);
118 }
119
120 device.appendChild(screen);
121
122 if (cfg.homeInd && cfg.device === 'phone') {
123 var hi = el('div');
124 hi.style.cssText = 'position:absolute;bottom:' + Math.round(fs / 2) + 'px;left:50%;transform:translateX(-50%);width:35%;height:4px;border-radius:2px;background:rgba(255,255,255,0.6);';
125 device.appendChild(hi);
126 }
127
128 outer.appendChild(device);
129 }
130
131 /* ── Laptop ── */
132 else if (cfg.device === 'laptop') {
133 var lidW = sw;
134 var lid = el('div');
135 lid.style.cssText = 'width:' + lidW + 'px;height:' + Math.round(lidW * 0.6) + 'px;background:' + frameColor + ';border-radius:12px 12px 0 0;padding:10px 10px 6px;box-sizing:border-box;position:relative;box-shadow:' + shadowVal + ';margin:0 auto;display:block;';
136
137 var screenArea = el('div');
138 screenArea.style.cssText = 'width:100%;height:100%;background:#000;border-radius:' + sr + 'px;overflow:hidden;position:relative;';
139 screenArea.appendChild(makeImg());
140 if (cfg.reflection) screenArea.appendChild(makeReflection());
141 lid.appendChild(screenArea);
142
143 var hinge = el('div');
144 hinge.style.cssText = 'width:' + Math.round(lidW * 0.15) + 'px;height:4px;background:' + frameColor + ';filter:brightness(0.7);margin:0 auto;display:block;';
145
146 var keyW = Math.round(lidW * 1.15);
147 var keybase = el('div');
148 keybase.style.cssText = 'width:' + keyW + 'px;height:' + Math.round(lidW * 0.08) + 'px;background:' + frameColor + ';filter:brightness(0.88);border-radius:0 0 8px 8px;margin:0 auto;display:block;position:relative;';
149
150 outer.appendChild(lid);
151 outer.appendChild(hinge);
152 outer.appendChild(keybase);
153 }
154
155 /* ── Browser ── */
156 else if (cfg.device === 'browser') {
157 var chromeH = cfg.browserChrome ? 38 : 0;
158 var container = el('div');
159 container.style.cssText = 'width:' + sw + 'px;border-radius:' + or + 'px;overflow:hidden;box-shadow:' + shadowVal + ';display:flex;flex-direction:column;border:1px solid rgba(0,0,0,0.12);';
160
161 if (cfg.browserChrome) {
162 var bar = el('div');
163 bar.style.cssText = 'display:flex;align-items:center;gap:6px;padding:0 12px;height:' + chromeH + 'px;background:' + (cfg.frameColor === 'black' ? '#1f2937' : '#f3f4f6') + ';border-bottom:1px solid rgba(0,0,0,0.1);flex-shrink:0;';
164
165 function dot(color) {
166 var d = el('div');
167 d.style.cssText = 'width:12px;height:12px;border-radius:50%;background:' + color + ';flex-shrink:0;';
168 return d;
169 }
170 bar.appendChild(dot('#ef4444'));
171 bar.appendChild(dot('#f59e0b'));
172 bar.appendChild(dot('#22c55e'));
173
174 var urlBar = el('div');
175 urlBar.style.cssText = 'flex:1;height:22px;background:#fff;border-radius:4px;border:1px solid rgba(0,0,0,0.1);display:flex;align-items:center;padding-left:8px;font-size:11px;color:#6b7280;overflow:hidden;white-space:nowrap;font-family:monospace;';
176 urlBar.textContent = cfg.browserUrl;
177 bar.appendChild(urlBar);
178 container.appendChild(bar);
179 }
180
181 var viewport = el('div');
182 viewport.style.cssText = 'width:100%;padding-bottom:' + (100 / ASPECTS.browser) + '%;position:relative;background:#fff;';
183 viewport.appendChild(makeImg());
184 if (cfg.reflection) viewport.appendChild(makeReflection());
185 container.appendChild(viewport);
186
187 outer.appendChild(container);
188 }
189
190 /* Hover lift handled by CSS (.bkdv-wrap[data-hover-lift="true"]) */
191
192 /* Scroll animation */
193 if (cfg.scrollAnim && !reducedMotion()) {
194 var io = new IntersectionObserver(function (entries) {
195 entries.forEach(function (entry) {
196 if (entry.isIntersecting) {
197 wrap.classList.add('bkdv-visible');
198 io.unobserve(wrap);
199 }
200 });
201 }, { threshold: 0.15 });
202 io.observe(wrap);
203 } else {
204 wrap.classList.add('bkdv-visible');
205 }
206
207 wrap.appendChild(outer);
208 }
209
210 function init() {
211 var wraps = document.querySelectorAll('.bkdv-wrap[data-device]');
212 wraps.forEach(function (wrap) { buildDevice(wrap); });
213 }
214
215 if (document.readyState === 'loading') {
216 document.addEventListener('DOMContentLoaded', init);
217 } else {
218 init();
219 }
220
221 }());
222