Setting the file. One moment.
Mobile Stage · Wix Harmony Editor · wix/skills · Skills Docs
ContentsBack to the top of the page scripts/copy/ mobile-stage.mjs
JavaScript · 56 lines · 5 KB
from
'playwright'
;
14
15 const [ mode , ... rest ] = process.argv. slice ( 2 );
16 if ( ! [ 'hide' , 'bg-opacity' ]. includes (mode)) { console. error ( 'usage: mobile-stage.mjs hide <id...> | bg-opacity <sectionId> <0-100>' ); process. exit ( 2 ); }
17 const b = await chromium. connectOverCDP ( `http://127.0.0.1:${ process . env . PW_PORT || 9333 }` );
18 const p = b. contexts (). flatMap (( c ) => c. pages ()). find (( x ) => x. url (). includes ( 'editor.wix.com/edit/' ));
19 if ( ! p) { console. error ( 'No Harmony editor page is open.' ); process. exit ( 3 ); }
20 const api = async ( code ) => { const r = await p. evaluate ( async ( code ) => { const a = await repluggableAppDebug.host. getAPI ({ name: 'RunEditorLLMCodeToolAPI' , public: true , layer: 'DATA_SERVICE' }); return a. execute ({ code }, { biParams: {} }); }, code); const c = JSON . parse (r.items[ 0 ].content); if ( ! c.success) throw new Error (c.summary); return c.result; };
21 await p. setViewportSize ({ width: 1600 , height: 1000 });
22 await p.keyboard. press ( 'Escape' ). catch (() => {});
23 const iframeEl = async () => p. $ ( 'iframe[class^="preview-"]' );
24 const stageRect = async ( id ) => { const ie = await iframeEl (); const ib = await ie. boundingBox (); const f = await ie. contentFrame (); const r = await f. evaluate (( id ) => { const e = document. getElementById (id) || document. querySelector ( `[id$="${ id }"]` ); if ( ! e) return null ; const q = e. getBoundingClientRect (); return { x: q.x, y: q.y, w: q.width, h: q.height, vw: innerWidth }; }, id); if ( ! r) return null ; const k = ib.width / r.vw; return { x: ib.x + r.x * k, y: ib.y + r.y * k, w: r.w * k, h: r.h * k }; };
25 const hiddenIn = ( id ) => api ( `const out = {}; for (const dev of ['mobile', 'desktop']) { await editorLLMApis.breakpoints.toggle({ device: dev }); const i = await editorLLMApis.components.inspect({ componentId: '${ id }', aspects: ['layout'], neighbourhood: false }); out[dev] = !!(i.members && i.members[0] && i.members[0].layout && i.members[0].layout.componentLayout && i.members[0].layout.componentLayout.hidden); } await editorLLMApis.breakpoints.toggle({ device: 'desktop' }); return out;` );
26 const out = [];
27
28 if (mode === 'hide' ) {
29 for ( const id of rest) {
30 await api ( `await editorLLMApis.breakpoints.toggle({ device: 'mobile' }); await editorLLMApis.components.select({ componentIds: ['${ id }'] }); return 1;` );
31 await p. waitForTimeout ( 800 );
32 let r = await stageRect (id);
33 for ( let i = 0 ; i < 12 && r && (r.y < 200 || r.y + r.h > 950 ); i ++ ) { await p.mouse. move ( 1500 , 600 ); await p.mouse. wheel ( 0 , Math. max ( - 900 , Math. min ( 900 , r.y - 450 ))); await p. waitForTimeout ( 500 ); r = await stageRect (id); }
34 if ( ! r) { out. push ({ id, error: 'not on the mobile stage' }); continue ; }
35 await p.mouse. click (r.x + r.w / 2 , r.y + r.h / 2 ); await p. waitForTimeout ( 600 );
36 await p.mouse. click (r.x + r.w / 2 , r.y + r.h / 2 , { button: 'right' }); await p. waitForTimeout ( 1000 );
37 const hide = p. locator ( 'text=Hide' ). first ();
38 if ( await hide. isVisible (). catch (() => false )) { await hide. click (); await p. waitForTimeout ( 1500 ); } else { out. push ({ id, error: 'no Hide in the context menu' }); await p.keyboard. press ( 'Escape' ); continue ; }
39 out. push ({ id, hidden: await hiddenIn (id) });
40 }
41 } else {
42 const [ id , value ] = rest;
43 const read = () => api ( `const out = {}; for (const dev of ['mobile', 'desktop']) { await editorLLMApis.breakpoints.toggle({ device: dev }); const f = (await editorLLMApis.appearance.getContainerBackground({ componentId: '${ id }' })).background.fields; const o = f.find((x) => x.key === 'backgroundMediaOpacity'); out[dev] = o && o.value ? o.value.raw : null; } await editorLLMApis.breakpoints.toggle({ device: 'desktop' }); return out;` );
44 const before = await read ();
45 await api ( `await editorLLMApis.breakpoints.toggle({ device: 'mobile' }); await editorLLMApis.components.select({ componentIds: ['${ id }'] }); return 1;` );
46 await p. waitForTimeout ( 1500 );
47 await p. getByText ( 'Replace Background' , { exact: true }). first (). click (); await p. waitForTimeout ( 2500 );
48 const inp = p. locator ( 'input[value="100"], input[value="' + Math. round ( Number (before.mobile ?? 1 ) * 100 ) + '"]' ). first ();
49 await inp. click ({ clickCount: 3 }); await p.keyboard. type ( String (value)); await p.keyboard. press ( 'Enter' ); await p. waitForTimeout ( 2000 );
50 await p.keyboard. press ( 'Escape' ). catch (() => {});
51 out. push ({ id, before, after: await read () });
52 }
53 await api ( `await editorLLMApis.breakpoints.toggle({ device: 'desktop' }); await editorLLMApis.site.save(); return 1;` );
54 out. push ({ isPublished: await api ( `return (await editorLLMApis.site.getStatus()).isPublished;` ) });
55 console. log ( JSON . stringify (out));
56 await b. close ();