@creaditor/web-starterkit 1.0.41 → 1.0.43

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,823 @@
1
+ "use strict";(("undefined"!=typeof self?self:this).webpackChunkCreaditor=("undefined"!=typeof self?self:this).webpackChunkCreaditor||[]).push([[2655],{72655(e,t,i){i.r(t),i.d(t,{NextButton:()=>P,PUBLISH_ERROR_EVENT:()=>L,PUBLISH_EVENT:()=>S});var s=i(59929),o=i(86319),n=i(93432),r=i(90090),a=i(86959),l=i(15604);const d=`${(0,a.Ay)()?"http://127.0.0.1:8000":"https://studio.creaditor.ai"}/api/seo-generate`;const c=s.qy`
2
+ <svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16" aria-hidden="true">
3
+ <path
4
+ d="M19 9l1.25-2.75L23 5l-2.75-1.25L19 1l-1.25 2.75L15 5l2.75 1.25L19 9zm-7.5.5L9 4 6.5 9.5 1 12l5.5 2.5L9 20l2.5-5.5L17 12l-5.5-2.5zM19 15l-1.25 2.75L15 19l2.75 1.25L19 23l1.25-2.75L23 19l-2.75-1.25L19 15z"
5
+ />
6
+ </svg>
7
+ `;class p extends s.WF{constructor(){super(),this.resolver=null,this.dismiss=()=>{this.isConnected&&this.remove()},this.onCancel=()=>{this.loading||(this.settle(null),this.dismiss())},this.onKeywordKeydown=e=>{"Enter"===e.key||","===e.key?(e.preventDefault(),this.commitDraftKeyword()):"Backspace"===e.key&&""===this.keywordDraft&&this.keywordList.length&&(this.keywordList=this.keywordList.slice(0,-1))},this.generateField=async e=>{if(this.loading||this.generatingField)return;const t=function(){const e=document.getElementById("main-page-wrapper");return(e?.innerText||"").trim()}();if(t){this.generatingField=e;try{const i="rtl"===this.direction?"he":"en",s=await this.requestSeo(e,t,i);if("keywords"===e){const e=(Array.isArray(s)?s:String(s).split(",")).map(e=>e.trim()).filter(Boolean),t=[...this.keywordList];for(const i of e)t.includes(i)||t.push(i);this.keywordList=t}else"title"===e?this.title=String(s).slice(0,100):this.description=String(s).slice(0,255)}catch(e){console.error("[seo-generate] failed:",e),this.snackbar(this.t("seo_generate_failed","Couldn't generate. Please try again."))}finally{this.generatingField=""}}else this.snackbar(this.t("seo_generate_empty","Add some content to the page first."))},this.onPublish=()=>{this.loading||(this.commitDraftKeyword(),this.loading=!0,this.settle({seo:{title:this.title.trim(),description:this.description.trim(),keywords:[...this.keywordList]},busy:e=>{this.isConnected&&(this.loading=e)},done:this.dismiss}))},this.loading=!1,this.title="",this.description="",this.keywordList=[],this.keywordDraft="",this.keywordsFocused=!1,this.generatingField=""}static open(){const e=document.createElement("cdtr-publish-seo"),t=o.M.get("app","seo")||{};return e.title=t.title||"",e.description=t.description||"",e.keywordList=(Array.isArray(t.keywords)?t.keywords:String(t.keywords||"").split(",")).map(e=>String(e).trim()).filter(Boolean),document.body.appendChild(e),e.waitForChoice()}waitForChoice(){return new Promise(e=>{this.resolver=e})}t(e,t){return o.M.get("lang",e)||t}get direction(){const e=o.M.get("theme");return e?.direction||"rtl"}settle(e){this.resolver&&(this.resolver(e),this.resolver=null)}commitDraftKeyword(){const e=this.keywordDraft.split(",").map(e=>e.trim()).filter(Boolean);if(!e.length)return;const t=[...this.keywordList];for(const i of e)t.includes(i)||t.push(i);this.keywordList=t,this.keywordDraft=""}removeKeyword(e){this.keywordList=this.keywordList.filter((t,i)=>i!==e)}snackbar(e){const t=o.M.get("commands");t?.snackbar?.(e)}async requestSeo(e,t,i){const s=async s=>{const o=await async function(){let e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];const t=l.Ay;if("function"==typeof t.studioTokenProvider)try{const i=await t.studioTokenProvider({forceRefresh:e});if("string"==typeof i&&i.length>0)return i}catch{}return"string"==typeof t.studioToken&&t.studioToken.length>0?t.studioToken:null}(s),n={"Content-Type":"application/json",Accept:"application/json"};return o&&(n.Authorization=`Bearer ${o}`),fetch(d,{method:"POST",headers:n,body:JSON.stringify({content:t,field:e,language:i})})};let o=await s(!1);if(401===o.status&&(o=await s(!0)),!o.ok)throw new Error(`HTTP ${o.status}`);const n=await o.json();if(!n.ok||void 0===n.value)throw new Error("bad response");return n.value}magicButton(e){const t=this.generatingField===e;return s.qy`
8
+ <button
9
+ class="magic"
10
+ type="button"
11
+ title=${this.t("seo_generate_tooltip","Generate with AI")}
12
+ aria-label=${this.t("seo_generate_tooltip","Generate with AI")}
13
+ ?disabled=${this.loading||!!this.generatingField}
14
+ @click=${()=>this.generateField(e)}
15
+ >
16
+ ${t?s.qy`<span class="mini-spinner"></span>`:c}
17
+ </button>
18
+ `}render(){const e=this.direction;return s.qy`
19
+ <div class="backdrop" @click=${this.onCancel}></div>
20
+ <div class="card" dir=${e}>
21
+ <h2 class="heading">${this.t("ready_to_publish","Ready to publish")}</h2>
22
+ <p class="subheading">
23
+ ${this.loading?this.t("publishing_your_site","Publishing your site…"):this.t("lets_set_some_seo","Let's set some SEO")}
24
+ </p>
25
+
26
+ <div class="field">
27
+ <div class="label-row">
28
+ <label>${this.t("seo_title_label","Page name for search engines and social networks (SEO)")}</label>
29
+ ${this.magicButton("title")}
30
+ </div>
31
+ <input
32
+ type="text"
33
+ maxlength=${100}
34
+ ?disabled=${this.loading}
35
+ .value=${this.title}
36
+ placeholder=${this.t("seo_title_placeholder","Page name as it will appear in search engines")}
37
+ @input=${e=>this.title=e.target.value}
38
+ />
39
+ <div class="counter">${this.title.length}/${100}</div>
40
+ </div>
41
+
42
+ <div class="field">
43
+ <div class="label-row">
44
+ <label>${this.t("seo_description_label","Page description for search engine and social network promotion (SEO)")}</label>
45
+ ${this.magicButton("description")}
46
+ </div>
47
+ <textarea
48
+ maxlength=${255}
49
+ ?disabled=${this.loading}
50
+ .value=${this.description}
51
+ placeholder=${this.t("seo_description_placeholder","This description will appear below the site title in search engines")}
52
+ @input=${e=>this.description=e.target.value}
53
+ ></textarea>
54
+ <div class="counter">${this.description.length}/${255}</div>
55
+ </div>
56
+
57
+ <div class="field">
58
+ <div class="label-row">
59
+ <label>${this.t("seo_keywords_label","Keywords")}</label>
60
+ ${this.magicButton("keywords")}
61
+ </div>
62
+ <div
63
+ class="chips ${this.keywordsFocused?"focused":""}"
64
+ @click=${e=>{const t=e.currentTarget.querySelector("input");t?.focus()}}
65
+ >
66
+ ${this.keywordList.map((e,t)=>s.qy`
67
+ <span class="chip">
68
+ ${e}
69
+ <button
70
+ type="button"
71
+ aria-label="remove"
72
+ @click=${e=>{e.stopPropagation(),this.removeKeyword(t)}}
73
+ >
74
+ ✕
75
+ </button>
76
+ </span>
77
+ `)}
78
+ <input
79
+ type="text"
80
+ ?disabled=${this.loading}
81
+ .value=${this.keywordDraft}
82
+ placeholder=${this.keywordList.length?"":this.t("seo_keywords_placeholder","For example: gift,woman,gift for woman")}
83
+ @input=${e=>this.keywordDraft=e.target.value}
84
+ @keydown=${this.onKeywordKeydown}
85
+ @focus=${()=>this.keywordsFocused=!0}
86
+ @blur=${()=>{this.keywordsFocused=!1,this.commitDraftKeyword()}}
87
+ />
88
+ </div>
89
+ </div>
90
+
91
+ <div class="actions">
92
+ <button class="publish" ?disabled=${this.loading} @click=${this.onPublish}>
93
+ ${this.loading?s.qy`<span class="spinner"></span>`:this.t("publish","Publish")}
94
+ </button>
95
+ <button class="cancel" ?disabled=${this.loading} @click=${this.onCancel}>
96
+ ${this.t("cancel","Cancel")}
97
+ </button>
98
+ </div>
99
+ </div>
100
+ `}}p.styles=s.AH`
101
+ :host {
102
+ position: fixed;
103
+ inset: 0;
104
+ z-index: var(--z-blocking, 2147483646);
105
+ display: flex;
106
+ align-items: center;
107
+ justify-content: center;
108
+ font-family: var(--font-family, Arial, Helvetica, sans-serif);
109
+ }
110
+ .backdrop {
111
+ position: absolute;
112
+ inset: 0;
113
+ background: rgba(26, 26, 46, 0.45);
114
+ animation: fade 0.2s ease forwards;
115
+ }
116
+ @keyframes fade {
117
+ from { opacity: 0; }
118
+ to { opacity: 1; }
119
+ }
120
+ .card {
121
+ position: relative;
122
+ background: #fff;
123
+ border-radius: 14px;
124
+ box-shadow: 0 24px 60px rgba(26, 26, 46, 0.28);
125
+ width: 560px;
126
+ max-width: 92vw;
127
+ max-height: 90vh;
128
+ overflow-y: auto;
129
+ padding: 34px 40px 30px;
130
+ box-sizing: border-box;
131
+ opacity: 0;
132
+ transform: scale(0.96);
133
+ animation: pop 0.28s cubic-bezier(0.18, 0.89, 0.32, 1.28) forwards;
134
+ }
135
+ @keyframes pop {
136
+ to { opacity: 1; transform: scale(1); }
137
+ }
138
+ .heading {
139
+ font-size: 26px;
140
+ font-weight: 700;
141
+ color: #1a1a2e;
142
+ margin: 0;
143
+ }
144
+ .subheading {
145
+ font-size: 17px;
146
+ font-weight: 600;
147
+ color: #8a8f9c;
148
+ margin: 10px 0 0;
149
+ }
150
+ .field {
151
+ margin-top: 26px;
152
+ }
153
+ label {
154
+ display: block;
155
+ font-size: 14px;
156
+ color: #3a3a4a;
157
+ margin-bottom: 8px;
158
+ }
159
+ .label-row {
160
+ display: flex;
161
+ align-items: center;
162
+ justify-content: space-between;
163
+ gap: 8px;
164
+ margin-bottom: 8px;
165
+ }
166
+ .label-row label {
167
+ margin-bottom: 0;
168
+ }
169
+ .magic {
170
+ flex: none;
171
+ display: inline-flex;
172
+ align-items: center;
173
+ justify-content: center;
174
+ width: 30px;
175
+ height: 30px;
176
+ border: 1px solid #d5d7de;
177
+ border-radius: 8px;
178
+ background: #fff;
179
+ color: var(--color-primary, #6366f1);
180
+ cursor: pointer;
181
+ line-height: 1;
182
+ transition: border-color 0.15s ease, background 0.15s ease;
183
+ }
184
+ .magic svg {
185
+ display: block;
186
+ }
187
+ .magic:hover:not(:disabled) {
188
+ border-color: var(--color-primary, #6366f1);
189
+ background: color-mix(in srgb, var(--primary, #6c5ce7) 10%, #fff);
190
+ }
191
+ .magic:disabled {
192
+ opacity: 0.5;
193
+ cursor: not-allowed;
194
+ }
195
+ .mini-spinner {
196
+ width: 14px;
197
+ height: 14px;
198
+ border: 2px solid color-mix(in srgb, var(--color-primary, #6366f1) 35%, transparent);
199
+ border-top-color: var(--color-primary, #6366f1);
200
+ border-radius: 50%;
201
+ animation: spin 0.8s linear infinite;
202
+ }
203
+ input,
204
+ textarea {
205
+ width: 100%;
206
+ box-sizing: border-box;
207
+ border: 1px solid #d5d7de;
208
+ border-radius: 8px;
209
+ padding: 12px 14px;
210
+ font-size: 15px;
211
+ font-family: inherit;
212
+ color: #1a1a2e;
213
+ outline: none;
214
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
215
+ }
216
+ input:focus,
217
+ textarea:focus {
218
+ /* --primary is the host's brand colour and may be a gradient, which is
219
+ invalid for border-color and color-mix — those hosts lost the focus
220
+ indicator entirely. The interaction colour is always flat. */
221
+ border-color: var(--color-primary, #6366f1);
222
+ box-shadow: 0 0 0 3px var(--color-primary-ring, rgba(99, 102, 241, 0.15));
223
+ }
224
+ textarea {
225
+ resize: vertical;
226
+ min-height: 84px;
227
+ }
228
+ input::placeholder,
229
+ textarea::placeholder {
230
+ color: #a7abb5;
231
+ }
232
+ .counter {
233
+ margin-top: 6px;
234
+ font-size: 12px;
235
+ color: #a7abb5;
236
+ }
237
+ .chips {
238
+ display: flex;
239
+ flex-wrap: wrap;
240
+ align-items: center;
241
+ gap: 8px;
242
+ border: 1px solid #d5d7de;
243
+ border-radius: 8px;
244
+ padding: 8px 10px;
245
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
246
+ }
247
+ .chips.focused {
248
+ border-color: var(--color-primary, #6366f1);
249
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary, #6366f1) 25%, transparent);
250
+ }
251
+ .chip {
252
+ display: inline-flex;
253
+ align-items: center;
254
+ gap: 6px;
255
+ /* Solid fallback first: if --primary carries a value color-mix can't
256
+ parse (e.g. a bare RGB triplet), the mix declaration is dropped and
257
+ this fixed tint keeps the chip visible. */
258
+ background: #eceafc;
259
+ background: color-mix(in srgb, var(--primary, #6c5ce7) 15%, #fff);
260
+ color: var(--color-primary, #6366f1);
261
+ border-radius: 6px;
262
+ padding: 5px 8px 5px 10px;
263
+ font-size: 14px;
264
+ line-height: 1;
265
+ white-space: nowrap;
266
+ }
267
+ .chip button {
268
+ display: inline-flex;
269
+ align-items: center;
270
+ justify-content: center;
271
+ width: 16px;
272
+ height: 16px;
273
+ border: none;
274
+ background: transparent;
275
+ color: inherit;
276
+ font-size: 15px;
277
+ line-height: 1;
278
+ cursor: pointer;
279
+ padding: 0;
280
+ opacity: 0.7;
281
+ }
282
+ .chip button:hover {
283
+ opacity: 1;
284
+ }
285
+ .chips input {
286
+ flex: 1;
287
+ min-width: 120px;
288
+ border: none;
289
+ padding: 4px;
290
+ box-shadow: none;
291
+ }
292
+ .chips input:focus {
293
+ border: none;
294
+ box-shadow: none;
295
+ }
296
+ .actions {
297
+ display: flex;
298
+ align-items: center;
299
+ justify-content: space-between;
300
+ margin-top: 34px;
301
+ }
302
+ .publish {
303
+ background: var(--primary, #6c5ce7);
304
+ color: #fff;
305
+ border: none;
306
+ border-radius: 8px;
307
+ padding: 14px 34px;
308
+ font-size: 16px;
309
+ font-weight: 600;
310
+ font-family: inherit;
311
+ cursor: pointer;
312
+ transition: filter 0.15s ease, opacity 0.15s ease;
313
+ }
314
+ .publish:hover {
315
+ filter: brightness(1.05);
316
+ }
317
+ .publish:disabled {
318
+ opacity: 0.6;
319
+ cursor: not-allowed;
320
+ }
321
+ .cancel {
322
+ background: none;
323
+ border: none;
324
+ color: #4a4a5a;
325
+ font-size: 16px;
326
+ font-family: inherit;
327
+ cursor: pointer;
328
+ padding: 8px;
329
+ }
330
+ .cancel:hover {
331
+ color: #1a1a2e;
332
+ }
333
+ .spinner {
334
+ display: inline-block;
335
+ width: 18px;
336
+ height: 18px;
337
+ border: 2px solid rgba(255, 255, 255, 0.5);
338
+ border-top-color: #fff;
339
+ border-radius: 50%;
340
+ animation: spin 0.8s linear infinite;
341
+ vertical-align: middle;
342
+ }
343
+ @keyframes spin {
344
+ to { transform: rotate(360deg); }
345
+ }
346
+ `,p.properties={loading:{type:Boolean},title:{type:String},description:{type:String},keywordList:{type:Array},keywordDraft:{type:String},keywordsFocused:{type:Boolean},generatingField:{type:String}},customElements.define("cdtr-publish-seo",p);class h extends s.WF{constructor(){super(),this.raf=0,this.dismissTimer=null,this.onKeyDown=e=>{"Escape"===e.key&&this.dismiss()},this.dismiss=()=>{this.isConnected&&this.remove()},this.copyLink=async()=>{if(this.url)try{await navigator.clipboard.writeText(this.url),this.copied=!0,setTimeout(()=>this.copied=!1,2e3)}catch{}},this.message="",this.sub="",this.url="",this.seoTitle="",this.seoDescription="",this.copied=!1}connectedCallback(){super.connectedCallback(),document.addEventListener("keydown",this.onKeyDown)}firstUpdated(){this.launchConfetti(),this.dismissTimer=setTimeout(()=>this.dismiss(),6500)}disconnectedCallback(){super.disconnectedCallback(),cancelAnimationFrame(this.raf),this.dismissTimer&&clearTimeout(this.dismissTimer),document.removeEventListener("keydown",this.onKeyDown)}t(e,t){return o.M.get("lang",e)||t}get direction(){const e=o.M.get("theme");return e?.direction||"rtl"}get host(){return this.url?this.url.replace(/^https?:\/\//,"").replace(/\/+$/,""):""}launchConfetti(){const e=this.renderRoot.querySelector("canvas");if(!e)return;const t=e.getContext("2d");if(!t)return;const i=window.devicePixelRatio||1,s=window.innerWidth,o=window.innerHeight;e.width=s*i,e.height=o*i,t.scale(i,i);const n=["#e94560","#1a1a2e","#f6c945","#2ec7a9","#4d7cfe","#ffffff"],r=s/2,a=.42*o,l=Math.min(220,Math.round(s/6)),d=Array.from({length:l},(e,t)=>{const i=2*Math.PI*t/l+t%3*.4,s=4+t%9;return{x:r,y:a,vx:Math.cos(i)*s,vy:Math.sin(i)*s-3,size:5+t%5,color:n[t%n.length],rot:t,vrot:(t%2?1:-1)*(.1+t%5*.03),life:1}}),c=performance.now(),p=e=>{const i=e-c;t.clearRect(0,0,s,o);let n=!1;for(const e of d)e.vy+=.16,e.x+=e.vx,e.y+=e.vy,e.rot+=e.vrot,i>2600*.55&&(e.life=Math.max(0,e.life-.02)),e.life>0&&e.y<o+40&&(n=!0),t.save(),t.globalAlpha=e.life,t.translate(e.x,e.y),t.rotate(e.rot),t.fillStyle=e.color,t.fillRect(-e.size/2,-e.size/2,e.size,.6*e.size),t.restore();n&&i<3e3?this.raf=requestAnimationFrame(p):t.clearRect(0,0,s,o)};this.raf=requestAnimationFrame(p)}renderPreview(){const e=this.host;if(!e)return s.s6;const t=(this.seoTitle||"").trim()||(this.seoDescription?"":e),i=(this.seoDescription||"").trim(),o=(t||e).charAt(0);return s.qy`
347
+ <div class="preview">
348
+ <p class="preview-caption">${this.t("search_preview_label","How your page will look on Google")}</p>
349
+ <div class="result-head">
350
+ <span class="favicon">${o}</span>
351
+ <div class="result-url">
352
+ <div class="result-host">${e.split("/")[0]}</div>
353
+ <div class="result-crumb">${e}</div>
354
+ </div>
355
+ </div>
356
+ ${t?s.qy`<p class="result-title">${t}</p>`:s.s6}
357
+ ${i?s.qy`<p class="result-desc">${i}</p>`:s.s6}
358
+ </div>
359
+ `}render(){const e=this.direction,t=this.copied?s.qy`<svg viewBox="0 0 24 24" fill="none"><path d="M5 13l4 4L19 7" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" /></svg>`:s.qy`<svg viewBox="0 0 24 24" fill="none"><rect x="9" y="9" width="11" height="11" rx="2" stroke="currentColor" stroke-width="2" /><path d="M5 15V5a2 2 0 0 1 2-2h10" stroke="currentColor" stroke-width="2" stroke-linecap="round" /></svg>`;return s.qy`
360
+ <canvas @click=${this.dismiss}></canvas>
361
+ <div class="card" dir=${e}>
362
+ <button
363
+ class="close"
364
+ type="button"
365
+ aria-label=${this.t("close","Close")}
366
+ title=${this.t("close","Close")}
367
+ @click=${this.dismiss}
368
+ >
369
+ <svg viewBox="0 0 24 24" fill="none"><path d="M6 6l12 12M18 6L6 18" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" /></svg>
370
+ </button>
371
+ <div class="check">
372
+ <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
373
+ <path d="M5 13l4 4L19 7" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" />
374
+ </svg>
375
+ </div>
376
+ <p class="title">${this.message||this.t("published","Published!")}</p>
377
+ <p class="sub">${this.sub||this.t("publishedSub","Your site is live.")}</p>
378
+
379
+ ${this.renderPreview()}
380
+
381
+ ${this.url?s.qy`
382
+ <div class="actions">
383
+ <a class="view" href=${this.url} target="_blank" rel="noopener">
384
+ <svg viewBox="0 0 24 24" fill="none"><path d="M14 4h6v6M20 4l-9 9M18 13v5a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
385
+ ${this.t("view_site","View site")}
386
+ </a>
387
+ <button class="copy" type="button" @click=${this.copyLink}>
388
+ ${t}
389
+ ${this.copied?this.t("link_copied","Link copied"):this.t("copy_link","Copy link")}
390
+ </button>
391
+ </div>
392
+ `:s.s6}
393
+ </div>
394
+ `}}h.styles=s.AH`
395
+ :host {
396
+ position: fixed;
397
+ inset: 0;
398
+ z-index: var(--z-blocking, 2147483646);
399
+ pointer-events: none;
400
+ display: block;
401
+ font-family: var(--font-family, Arial, Helvetica, sans-serif);
402
+ }
403
+ canvas {
404
+ position: absolute;
405
+ inset: 0;
406
+ width: 100%;
407
+ height: 100%;
408
+ }
409
+ .card {
410
+ position: absolute;
411
+ top: 50%;
412
+ left: 50%;
413
+ transform: translate(-50%, -50%) scale(0.9);
414
+ background: #ffffff;
415
+ border-radius: 20px;
416
+ box-shadow: 0 30px 80px rgba(26, 26, 46, 0.32);
417
+ padding: 36px 40px 32px;
418
+ text-align: center;
419
+ pointer-events: auto;
420
+ opacity: 0;
421
+ animation: pop 0.44s cubic-bezier(0.18, 0.89, 0.32, 1.28) forwards;
422
+ width: 460px;
423
+ max-width: 90vw;
424
+ box-sizing: border-box;
425
+ }
426
+ @keyframes pop {
427
+ to {
428
+ opacity: 1;
429
+ transform: translate(-50%, -50%) scale(1);
430
+ }
431
+ }
432
+ /* Manual dismiss. The card also auto-closes, but the confetti + preview
433
+ invite lingering — the user needs a way out on their own terms.
434
+ inset-inline-end so it lands top-left in the RTL card, top-right in LTR. */
435
+ .close {
436
+ position: absolute;
437
+ top: 12px;
438
+ inset-inline-end: 12px;
439
+ width: 32px;
440
+ height: 32px;
441
+ display: flex;
442
+ align-items: center;
443
+ justify-content: center;
444
+ padding: 0;
445
+ border: none;
446
+ border-radius: 50%;
447
+ background: transparent;
448
+ color: #a7abb5;
449
+ cursor: pointer;
450
+ transition: background 0.15s ease, color 0.15s ease;
451
+ }
452
+ .close:hover {
453
+ background: #f1f2f6;
454
+ color: #1a1a2e;
455
+ }
456
+ .close svg {
457
+ width: 16px;
458
+ height: 16px;
459
+ }
460
+ .check {
461
+ width: 68px;
462
+ height: 68px;
463
+ border-radius: 50%;
464
+ background: #2ec7a9;
465
+ margin: 0 auto 18px;
466
+ display: flex;
467
+ align-items: center;
468
+ justify-content: center;
469
+ box-shadow: 0 0 0 0 rgba(46, 199, 169, 0.45);
470
+ animation: ring 1.6s ease-out 0.2s;
471
+ }
472
+ @keyframes ring {
473
+ 0% { box-shadow: 0 0 0 0 rgba(46, 199, 169, 0.45); }
474
+ 70% { box-shadow: 0 0 0 18px rgba(46, 199, 169, 0); }
475
+ 100% { box-shadow: 0 0 0 0 rgba(46, 199, 169, 0); }
476
+ }
477
+ .check svg {
478
+ width: 34px;
479
+ height: 34px;
480
+ }
481
+ .title {
482
+ font-size: 24px;
483
+ font-weight: 700;
484
+ color: #1a1a2e;
485
+ margin: 0;
486
+ }
487
+ .sub {
488
+ font-size: 14px;
489
+ color: #8a8f9c;
490
+ margin: 8px 0 0;
491
+ }
492
+
493
+ /* Google-style search-result preview — the payoff for the SEO step. */
494
+ .preview {
495
+ margin-top: 22px;
496
+ border: 1px solid #e6e8ee;
497
+ border-radius: 12px;
498
+ padding: 14px 16px;
499
+ text-align: start;
500
+ background: #fbfbfd;
501
+ }
502
+ .preview-caption {
503
+ font-size: 11px;
504
+ font-weight: 600;
505
+ letter-spacing: 0.02em;
506
+ text-transform: uppercase;
507
+ color: #a7abb5;
508
+ margin: 0 0 10px;
509
+ }
510
+ .result-head {
511
+ display: flex;
512
+ align-items: center;
513
+ gap: 8px;
514
+ }
515
+ .favicon {
516
+ flex: none;
517
+ width: 26px;
518
+ height: 26px;
519
+ border-radius: 50%;
520
+ background: var(--primary, #6c5ce7);
521
+ color: #fff;
522
+ display: flex;
523
+ align-items: center;
524
+ justify-content: center;
525
+ font-size: 13px;
526
+ font-weight: 700;
527
+ text-transform: uppercase;
528
+ }
529
+ .result-url {
530
+ min-width: 0;
531
+ }
532
+ .result-host {
533
+ font-size: 13px;
534
+ color: #1a1a2e;
535
+ line-height: 1.2;
536
+ white-space: nowrap;
537
+ overflow: hidden;
538
+ text-overflow: ellipsis;
539
+ /* URLs read left-to-right even in an RTL card. */
540
+ direction: ltr;
541
+ text-align: start;
542
+ }
543
+ .result-crumb {
544
+ font-size: 12px;
545
+ color: #6a7280;
546
+ line-height: 1.2;
547
+ white-space: nowrap;
548
+ overflow: hidden;
549
+ text-overflow: ellipsis;
550
+ direction: ltr;
551
+ text-align: start;
552
+ }
553
+ .result-title {
554
+ margin: 8px 0 0;
555
+ font-size: 18px;
556
+ line-height: 1.3;
557
+ color: #1a56db;
558
+ font-weight: 500;
559
+ overflow: hidden;
560
+ text-overflow: ellipsis;
561
+ display: -webkit-box;
562
+ -webkit-line-clamp: 1;
563
+ -webkit-box-orient: vertical;
564
+ }
565
+ .result-desc {
566
+ margin: 4px 0 0;
567
+ font-size: 13px;
568
+ line-height: 1.5;
569
+ color: #4d5562;
570
+ overflow: hidden;
571
+ text-overflow: ellipsis;
572
+ display: -webkit-box;
573
+ -webkit-line-clamp: 2;
574
+ -webkit-box-orient: vertical;
575
+ }
576
+
577
+ .actions {
578
+ display: flex;
579
+ align-items: center;
580
+ justify-content: center;
581
+ gap: 10px;
582
+ margin-top: 24px;
583
+ }
584
+ .view {
585
+ display: inline-flex;
586
+ align-items: center;
587
+ gap: 8px;
588
+ background: var(--primary, #6c5ce7);
589
+ color: #fff;
590
+ text-decoration: none;
591
+ font-size: 15px;
592
+ font-weight: 600;
593
+ padding: 12px 26px;
594
+ border-radius: 10px;
595
+ transition: filter 0.15s ease;
596
+ }
597
+ .view:hover {
598
+ filter: brightness(1.06);
599
+ }
600
+ .view svg {
601
+ width: 16px;
602
+ height: 16px;
603
+ }
604
+ .copy {
605
+ display: inline-flex;
606
+ align-items: center;
607
+ gap: 6px;
608
+ background: #fff;
609
+ color: #4a4a5a;
610
+ border: 1px solid #d5d7de;
611
+ font-size: 15px;
612
+ font-family: inherit;
613
+ font-weight: 500;
614
+ padding: 12px 18px;
615
+ border-radius: 10px;
616
+ cursor: pointer;
617
+ transition: border-color 0.15s ease, color 0.15s ease;
618
+ }
619
+ .copy:hover {
620
+ border-color: var(--color-primary, #6366f1);
621
+ color: #1a1a2e;
622
+ }
623
+ .copy svg {
624
+ width: 15px;
625
+ height: 15px;
626
+ }
627
+ `,h.properties={message:{type:String},sub:{type:String},url:{type:String},seoTitle:{type:String},seoDescription:{type:String},copied:{type:Boolean}},customElements.define("cdtr-publish-success",h);var u=i(19623),f=i(2285),g=i(69600);const b=l.Ay,x=e=>{if(!e.fix)return!1;let t=!1;for(const i of e.fix.patches){const e=o.M.get("components",i.id);e&&(b.store().execCommand2({transactions:[{key:i.key,value:i.value}],update:[e]}),t=!0)}return t},m=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return(o.M.get("lang",e)||e).replace(/\{(\w+)\}/g,(e,i)=>null!=t[i]?String(t[i]):"")},y=e=>{const t=e.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i);return t?"#"+t.slice(1,4).map(e=>Number(e).toString(16).padStart(2,"0")).join(""):e},w=e=>new Promise(t=>setTimeout(t,e)),v=()=>!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches,k=e=>`${e.ruleId}|${e.elementIds.join(",")}`,$=e=>e.filter(e=>"error"===e.severity).length,_={"col-grid":"inbox","block-too-wide":"inbox","gmail-clip":"inbox","wider-than-container":"phone","fixed-without-max":"phone","cramped-columns":"phone"};class z extends s.WF{constructor(){super(),this.resolve=()=>{},this.htmlBytes=void 0,this.fixedTimer=void 0,this.findings=[],this.collapsed=!1,this.open={},this.fixing=new Set,this.fixedCount=0,this.analyzing=!1,this.stage="",this.stageCount=0,this.autoFixed=0,this.addEventListener("click",e=>{e.composedPath()[0]===this&&this.dismiss()}),this.onKeydown=this.onKeydown.bind(this)}connectedCallback(){super.connectedCallback(),document.addEventListener("keydown",this.onKeydown)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("keydown",this.onKeydown)}onKeydown(e){"Escape"===e.key&&this.dismiss()}dismiss(){this.collapsed||this.stage||this.fixing.size>0||this.analyzing||this.resolve("edit")}get groups(){return(0,u.kG)(this.findings)}isOpen(e,t){return this.open[e.id]??0===t}toggle(e,t){this.open={...this.open,[e.id]:!this.isOpen(e,t)}}rerun(){this.findings=(0,u.JT)((0,f.D)(),{channel:(0,f.l)(),htmlBytes:this.htmlBytes})}async runFixes(e){!this.fixing.size&&e.length&&(this.fixing=new Set(e.map(k)),await w(v()?0:1100),e.forEach(x),await w(60),this.rerun(),this.fixing=new Set,this.fixedCount=e.reduce((e,t)=>e+t.count,0),clearTimeout(this.fixedTimer),this.fixedTimer=setTimeout(()=>this.fixedCount=0,2400))}fix(e){this.runFixes([e])}fixGroup(e){this.runFixes(e.items.filter(e=>e.fix))}show(e){this.collapsed=!0,(e=>{const t=o.M.get("components",e);t&&(b.clean().selectComponent(t),setTimeout(()=>{const t=document.querySelector(`[data-id="${CSS.escape(e)}"]`);if(!t)return;const i=t.closest(".amazingbar-content-wrapper");if(i){const e=i.getBoundingClientRect(),s=t.getBoundingClientRect();i.scrollTop+=s.top-e.top-(i.clientHeight-s.height)/2}else t.scrollIntoView({block:"center"})},300))})(e.elementIds[0]||e.elementId)}async analyze(e){this.analyzing=!0;try{const[t]=await Promise.all([e(),w(v()?0:600)]);this.findings=t.findings,void 0!==t.htmlBytes&&(this.htmlBytes=t.htmlBytes)}finally{this.analyzing=!1}}expand(){this.collapsed=!1,this.analyze(()=>({findings:(0,u.JT)((0,f.D)(),{channel:(0,f.l)(),htmlBytes:this.htmlBytes})}))}get canFixAndContinue(){const e=this.findings.filter(e=>"error"===e.severity);return e.length>0&&e.every(e=>e.fix)}async fixAndContinue(){const e=this.groups.flatMap(e=>e.items).filter(e=>"error"===e.severity&&e.fix);await this.runFixes(e),$(this.findings)||setTimeout(()=>this.resolve("continue"),v()?0:700)}renderSample(e){const t=e.message.params||{},i=e=>"string"==typeof e&&/^[#\w(),.%\s]+$/.test(e);return i(t.color)&&i(t.background)?s.qy`<div class="sample">
628
+ <b style="color:${t.color};background:${t.background}">Aa אב</b>
629
+ <code dir="ltr">${y(String(t.color))} / ${y(String(t.background))}</code>
630
+ </div>`:null}renderOnlyShows(e){const t=_[e.ruleId];if(!t)return null;const i="phone"===t?s.qy`<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="7" y="2" width="10" height="20" rx="2" /><path d="M11 18h2" /></svg>`:s.qy`<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2" /><path d="m3 7 9 6 9-6" /></svg>`;return s.qy`<span class="only-shows" title=${m("preflight_only_shows_hint")}>${i}${m(`preflight_only_${t}`)}</span>`}renderStage(){const e=this.stageCount,t="checking"===this.stage?s.qy`<span class="spark" aria-hidden="true">✦</span><div><b>${m("preflight_checking")}</b></div>`:"fixing"===this.stage?s.qy`<span class="spark" aria-hidden="true">✦</span><div>
631
+ <b>${m("preflight_found_breaking",{count:e})}</b><small>${m("preflight_fixing_breaking")}</small></div>`:s.qy`<span class="ok" aria-hidden="true">✓</span><div><b>${m("preflight_fixed_breaking",{count:e})}</b></div>`;return s.qy`<div class="pop" role="status" aria-live="polite">${t}</div>`}renderAnalyzing(){return s.qy`<div class="card" role="dialog" aria-modal="true" aria-labelledby="pf-title" aria-busy="true">
632
+ <header>
633
+ <div>
634
+ <h2 id="pf-title">${m("preflight_title")}</h2>
635
+ <p class="ai-note">${m("preflight_ai_note")}</p>
636
+ </div>
637
+ </header>
638
+ <div class="analyzing" role="status">
639
+ <span class="spark" aria-hidden="true">✦</span>${m("preflight_analyzing")}
640
+ </div>
641
+ <div class="groups">
642
+ ${[0,1,2].map(()=>s.qy`<div class="skeleton"></div>`)}
643
+ </div>
644
+ <footer>
645
+ <button @click=${()=>this.resolve("edit")}>${m("preflight_back")}</button>
646
+ </footer>
647
+ </div>`}renderGroup(e,t){const i=this.isOpen(e,t),o=e.items.filter(e=>e.fix);return s.qy`<section class=${e.id} ?data-open=${i}>
648
+ <div class="head" role="button" tabindex="0" aria-expanded=${i?"true":"false"}
649
+ @click=${()=>this.toggle(e,t)}
650
+ @keydown=${i=>("Enter"===i.key||" "===i.key)&&(i.preventDefault(),this.toggle(e,t))}>
651
+ <span class="chev">▸</span>
652
+ <h3>${m(`preflight_group_${e.id}`)}</h3>
653
+ <span class="badge">${e.items.reduce((e,t)=>e+t.count,0)}</span>
654
+ ${o.length?s.qy`<button class="fix-all" ?disabled=${this.fixing.size>0}
655
+ @click=${t=>{t.stopPropagation(),this.fixGroup(e)}}>
656
+ ${o.some(e=>this.fixing.has(k(e)))?s.qy`<span class="spark" aria-hidden="true">✦</span> ${m("preflight_fixing")}`:m("preflight_fix_group",{count:o.reduce((e,t)=>e+t.count,0)})}
657
+ </button>`:null}
658
+ </div>
659
+ ${i?s.qy`<ul>
660
+ ${e.items.map(e=>s.qy`<li class=${this.fixing.has(k(e))?"fixing":""}>
661
+ <span class="text">${m(e.message.key,e.message.params||{})}${e.count>1?s.qy` <bdi class="times">×${e.count}</bdi>`:null}${this.renderSample(e)}${this.renderOnlyShows(e)}</span>
662
+ <button @click=${()=>this.show(e)}>${m("preflight_show")}</button>
663
+ ${e.fix?s.qy`<button ?disabled=${this.fixing.size>0} @click=${()=>this.fix(e)}>
664
+ ${this.fixing.has(k(e))?s.qy`<span class="spark" aria-hidden="true">✦</span>`:null}${m(e.fix.label)}
665
+ </button>`:null}
666
+ </li>`)}
667
+ </ul>`:null}
668
+ </section>`}render(){const e=this.findings.length;if(this.collapsed)return s.qy`<button class="primary" @click=${this.expand}>${m("preflight_title")} (${e})</button>`;if(this.stage)return this.renderStage();if(this.analyzing)return this.renderAnalyzing();const t=$(this.findings);let i;return i=t?this.canFixAndContinue?s.qy`<button class="primary" ?disabled=${this.fixing.size>0} @click=${this.fixAndContinue}>
669
+ ${this.fixing.size?s.qy`<span class="spark" aria-hidden="true">✦</span> ${m("preflight_fixing")}`:m("preflight_fix_and_continue")}
670
+ </button>`:s.qy`<button class="primary" @click=${()=>this.resolve("continue")}>${m("preflight_continue_anyway")}</button>`:s.qy`<button class="primary" @click=${()=>this.resolve("continue")}>${m("preflight_continue")}</button>`,s.qy`<div class="card" role="dialog" aria-modal="true" aria-labelledby="pf-title">
671
+ <header>
672
+ <div>
673
+ <h2 id="pf-title">${m("preflight_title")}</h2>
674
+ <p class="ai-note">${m("preflight_ai_note")}</p>
675
+ </div>
676
+ <span class="summary ${t?"bad":""}">
677
+ ${t?m("preflight_must_fix",{count:t}):m("preflight_nothing_must_fix")}
678
+ </span>
679
+ </header>
680
+ ${this.autoFixed?s.qy`<div class="auto-note">✨ ${m("preflight_auto_fixed",{count:this.autoFixed})}</div>`:null}
681
+ ${this.fixedCount?s.qy`<div class="fixed-note" role="status">✨ ${m("preflight_fixed_count",{count:this.fixedCount})}</div>`:null}
682
+ <div class="groups">
683
+ ${this.findings.length?this.groups.map((e,t)=>this.renderGroup(e,t)):s.qy`<p class="all-good">✓ ${m("preflight_all_good")}</p>`}
684
+ </div>
685
+ <footer>
686
+ <button @click=${()=>this.resolve("edit")}>${m("preflight_back")}</button>
687
+ ${i}
688
+ </footer>
689
+ </div>`}}z.properties={findings:{attribute:!1},collapsed:{type:Boolean,reflect:!0},open:{attribute:!1},fixing:{attribute:!1},fixedCount:{attribute:!1},analyzing:{attribute:!1},stage:{type:String,reflect:!0},stageCount:{attribute:!1},autoFixed:{attribute:!1}},z.styles=s.AH`
690
+ :host { position: fixed; inset: 0; display: grid; place-items: center; background: rgb(15 23 42 / 0.35); font: 14px/1.5 system-ui, sans-serif; color: #0f172a; }
691
+ :host([stage]:not([stage=""])) { inset: auto; display: block; background: none; }
692
+ .pop { width: 290px; padding: 14px 16px; background: #fff; border-radius: 12px; box-shadow: 0 12px 32px rgb(0 0 0 / 0.18);
693
+ border: 1px solid #eef0f3; display: flex; gap: 10px; align-items: flex-start; animation: pop 0.25s ease-out; }
694
+ .pop .spark { margin: 2px 0 0; font-size: 15px; }
695
+ .pop b { display: block; font-size: 14px; }
696
+ .pop small { display: block; margin-top: 2px; color: #64748b; font-size: 12.5px; }
697
+ .pop .ok { color: #16a34a; font-size: 16px; line-height: 1.2; }
698
+ .auto-note { margin: 10px 12px 0; padding: 8px 12px; border-radius: 10px; font-size: 13px; color: #166534;
699
+ background: linear-gradient(90deg, #ecfdf5, #f5f3ff); }
700
+ :host([collapsed]) { inset: auto; inset-block-end: 16px; inset-inline-end: 16px; background: none; }
701
+ .card { width: min(580px, calc(100vw - 32px)); max-height: 80vh; display: flex; flex-direction: column; background: #fff; border-radius: 12px; box-shadow: 0 20px 50px rgb(0 0 0 / 0.25); }
702
+ header { padding: 16px 20px; border-bottom: 1px solid #eef0f3; display: flex; justify-content: space-between; align-items: center; gap: 12px; }
703
+ h2 { margin: 0; font-size: 16px; }
704
+ .ai-note { margin: 2px 0 0; font-size: 12.5px; color: #64748b; }
705
+ .summary { font-size: 13px; color: #64748b; }
706
+ .summary.bad { color: #b91c1c; font-weight: 600; }
707
+ .groups { overflow: auto; padding: 8px 12px; }
708
+ section { border: 1px solid #eef0f3; border-radius: 10px; margin: 8px 0; overflow: hidden; }
709
+ section.mobile { border-color: #fecaca; }
710
+ section.missing { border-color: #fed7aa; }
711
+ .head { display: flex; align-items: center; gap: 10px; padding: 10px 12px; cursor: pointer; background: #f8fafc; }
712
+ section.mobile .head { background: #fef2f2; }
713
+ section.missing .head { background: #fff7ed; }
714
+ .head h3 { margin: 0; font-size: 14px; flex: 1; }
715
+ .chev { transition: transform 0.15s; color: #64748b; }
716
+ section[data-open] .chev { transform: rotate(90deg); }
717
+ :host([dir="rtl"]) section:not([data-open]) .chev { transform: rotate(180deg); }
718
+ .badge { min-width: 20px; padding: 0 6px; border-radius: 10px; background: #e2e8f0; font-size: 12px; text-align: center; }
719
+ section.mobile .badge { background: #dc2626; color: #fff; }
720
+ section.missing .badge { background: #ea580c; color: #fff; }
721
+ ul { list-style: none; margin: 0; padding: 0 12px 6px; }
722
+ li { display: flex; gap: 8px; align-items: center; padding: 8px 0; border-top: 1px solid #f3f4f6; }
723
+ .text { flex: 1; }
724
+ .times { color: #64748b; font-size: 12px; margin-inline-start: 6px; }
725
+ .sample { display: flex; width: fit-content; align-items: center; gap: 6px; margin-top: 4px; font-size: 12px; color: #64748b; }
726
+ .sample b { padding: 2px 10px; border-radius: 6px; border: 1px solid #e2e8f0; font-size: 15px; }
727
+ .sample code { font: 11px ui-monospace, monospace; }
728
+ button { font: inherit; border-radius: 8px; padding: 5px 11px; border: 1px solid #d0d5dd; background: #fff; color: inherit; cursor: pointer; white-space: nowrap; }
729
+ button.primary { background: #4f46e5; border-color: #4f46e5; color: #fff; }
730
+ button.fix-all { background: #111827; border-color: #111827; color: #fff; }
731
+ button:disabled { cursor: default; opacity: 0.85; }
732
+ li { position: relative; transition: opacity 0.3s; }
733
+ li.fixing { border-radius: 8px; }
734
+ li.fixing::after {
735
+ content: ""; position: absolute; inset: 2px -6px; border-radius: 8px; pointer-events: none;
736
+ background: linear-gradient(100deg, transparent 20%, rgb(139 92 246 / 0.16) 40%, rgb(236 72 153 / 0.18) 50%, rgb(59 130 246 / 0.16) 60%, transparent 80%);
737
+ background-size: 250% 100%; animation: shimmer 1.1s ease-in-out infinite;
738
+ }
739
+ li.fixing .text { opacity: 0.55; }
740
+ .spark { display: inline-block; margin-inline-end: 4px; animation: spin 1s linear infinite; color: #a855f7; }
741
+ button.fix-all .spark, button.primary .spark { color: #f0abfc; }
742
+ .all-good { margin: 18px 8px; font-weight: 600; color: #166534; }
743
+ .fixed-note { margin: 10px 12px 0; padding: 8px 12px; border-radius: 10px; font-weight: 600; color: #166534;
744
+ background: linear-gradient(90deg, #ecfdf5, #f5f3ff); animation: pop 0.35s ease-out; }
745
+ @keyframes shimmer { from { background-position: 125% 0; } to { background-position: -125% 0; } }
746
+ @keyframes spin { to { transform: rotate(360deg); } }
747
+ @keyframes pop { from { opacity: 0; transform: translateY(-4px) scale(0.98); } to { opacity: 1; transform: none; } }
748
+ @media (prefers-reduced-motion: reduce) { li.fixing::after, .spark, .fixed-note { animation: none; } }
749
+ .only-shows { display: flex; width: fit-content; align-items: center; gap: 4px; margin-top: 4px; padding: 1px 8px 1px 6px;
750
+ border-radius: 999px; background: #f5f3ff; color: #6d28d9; font-size: 11.5px; font-weight: 600; }
751
+ .only-shows svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
752
+ .analyzing { display: flex; align-items: center; gap: 4px; padding: 14px 20px 4px; font-weight: 600; color: #6d28d9; }
753
+ .skeleton { height: 44px; margin: 8px 0; border-radius: 10px;
754
+ background: linear-gradient(100deg, #f3f4f6 20%, #ede9fe 50%, #f3f4f6 80%); background-size: 250% 100%;
755
+ animation: shimmer 1.1s ease-in-out infinite; }
756
+ @media (prefers-reduced-motion: reduce) { .skeleton { animation: none; } }
757
+ footer { padding: 14px 20px; display: flex; gap: 8px; justify-content: flex-end; border-top: 1px solid #eef0f3; flex-wrap: wrap; }
758
+ `,customElements.get("cdtr-preflight")||customElements.define("cdtr-preflight",z);const C={check:(e,t)=>new Promise((i,s)=>{const n=document.createElement("cdtr-preflight");n.dir=(()=>{const e=o.M.get("theme");if("rtl"===e?.direction||"ltr"===e?.direction)return e.direction;const t=getComputedStyle(document.documentElement).getPropertyValue("--direction-locale").trim();if("rtl"===t||"ltr"===t)return t;const i=String(o.M.get("config","language")||"");return/^(he|ar|fa|ur)/i.test(i)?"rtl":"ltr"})(),n.style.zIndex=String(Number((0,g.A)())+10);(()=>{const t=e.getBoundingClientRect();n.style.top=`${Math.round(t.bottom+8)}px`;const i="rtl"===n.dir?t.left:t.right-290;n.style.left=`${Math.max(8,Math.min(Math.round(i),window.innerWidth-298))}px`})(),n.stage="checking",n.resolve=e=>{n.remove(),i(e)},document.body.appendChild(n);const r=e=>w(v()?0:e);(async()=>{const[e]=await Promise.all([t(),r(700)]);n.htmlBytes=e.htmlBytes;let i=e.findings;const s=(e=>e.filter(e=>e.fix&&_[e.ruleId]))(i);s.length&&(n.stageCount=s.length,n.stage="fixing",await r(1200),s.forEach(x),await w(60),i=(0,u.JT)((0,f.D)(),{channel:(0,f.l)(),htmlBytes:n.htmlBytes}),n.stage="fixed",await r(900)),i.length?(n.findings=i,n.autoFixed=s.length,n.style.top=n.style.left="",n.stage=""):n.resolve("continue")})().catch(e=>{n.remove(),s(e)})})};const S="creaditor:publish",L="creaditor:publish-error",T=async()=>{const e=(0,f.l)(),t=await async function(e){if("newsletter"===e)try{const e=await Promise.race([(0,n.FE)("newsletter"),new Promise(e=>setTimeout(()=>e(void 0),8e3))]);return"string"==typeof e?new Blob([e]).size:void 0}catch{return}}(e);return{findings:(0,u.JT)((0,f.D)(),{channel:e,htmlBytes:t}),htmlBytes:t}};class P extends s.WF{constructor(){super(),this.preflightOpen=!1,this.channel="",this.isLoading=!1,this.isLocked=!1,this.lockTimer=null}connectedCallback(){super.connectedCallback(),this.onNextStep||(this.onNextStep=o.M.get("config","onNextStep")),this.onPublish||(this.onPublish=o.M.get("config","onPublish")),this.channel||(this.channel=o.M.get("config","channel")||"")}disconnectedCallback(){super.disconnectedCallback(),this.clearTimers()}clearTimers(){this.lockTimer&&(clearTimeout(this.lockTimer),this.lockTimer=null)}async onNextClick(){if(this.isLocked||this.isLoading)return;if(this.preflightOpen)return void document.querySelector("cdtr-preflight")?.expand?.();if("newsletter"!==(0,f.l)())return this.handleClick();let e="continue";this.preflightOpen=!0;try{e=await C.check(this,T)}catch(t){console.warn("[preflight] checks failed",t),e="continue"}finally{this.preflightOpen=!1}"continue"===e&&await this.handleClick()}async handleClick(){if(this.isLocked||this.isLoading)return;document.querySelector("cdtr-preflight")?.resolve?.("edit");const e=!!o.M.get("config","access"),t="web"===this.channel,i=e&&t;let s=null;if(t&&(s=await p.open(),!s))return;const a=s?s.seo:null;this.isLoading=!0,this.isLocked=!0;const l=Date.now();this.lockTimer=setTimeout(()=>{this.clearTimers(),this.isLoading=!1,this.isLocked=!1},1e4);try{if(t&&s){let e=!1;try{i&&a&&(await(0,r.YE)({seo:a}),await(0,r.bK)({})),"function"==typeof this.onPublish?e=await this.runHostPublish(this.onPublish,a,i,s):"function"==typeof this.onNextStep&&await this.onNextStep({toHTML:n.FE,toJSON:n.U2,seo:a??void 0})}finally{s.done()}return void(e||(this.emitPublished(i,a),this.celebratePublish(a)))}const e=o.M.get("config","editor","props","onSave"),l=Date.now();"function"==typeof e&&await e({transactions:[],toJson:n.U2,toJSON:n.U2,toHTML:n.FE});const d=Date.now()-l;d<3e3&&await new Promise(e=>setTimeout(e,3e3-d)),"function"==typeof this.onNextStep&&await this.onNextStep({toHTML:n.FE,toJSON:n.U2}),this.emitPublished(i,a)}catch(e){console.error("Error in publish/onNextStep:",e),this.emitPublishError(i,a,e),this.snackbar(o.M.get("lang","publishError")||"Publish failed")}finally{const e=Date.now()-l;e<400&&await new Promise(t=>setTimeout(t,400-e)),this.clearTimers(),this.isLoading=!1,this.isLocked=!1}}runHostPublish(e,t,i,s){return new Promise(a=>{let l=!1;const d=(e,n,r)=>{l||(l=!0,clearTimeout(c),s.done(),e?(this.celebratePublish(t),this.emitPublished(i,t)):(this.snackbar(r||o.M.get("lang","publishError")||"Publish failed"),this.emitPublishError(i,t,n)),a(!0))},c=setTimeout(()=>{l||(console.warn("config.onPublish never signalled completion — finishing the publish without it. Call success() or error() (or return a promise) so the modal can come down."),l=!0,s.done(),a(!1))},6e4),p={title:t.title,description:t.description,keywords:t.keywords},h={loading:function(){let e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];return s.busy(e)},success:()=>d(!0),confetti:()=>d(!0),error:e=>d(!1,new Error(e||"host publish failed"),e),commands:{patchSite:e=>(0,r.YE)(e??{}),publishSite:e=>(0,r.bK)(e??{}),toHTML:n.FE,toJSON:n.U2}};let u;try{u=e(p,h)}catch(e){return console.error("Error in config.onPublish:",e),void d(!1,e)}u&&"function"==typeof u.then&&Promise.resolve(u).then(()=>d(!0),e=>{console.error("Error in config.onPublish:",e),d(!1,e)})})}snackbar(e){const t=o.M.get("commands");t?.snackbar?.(e)}siteUrl(){const e=o.M.get("app","domains"),t=e?.[0]?.name;if(t)return/^https?:\/\//.test(t)?t:`https://${t}`}emitPublished(e,t){const i={channel:this.channel,selfPublish:e,seo:t??void 0,url:this.siteUrl(),toHTML:n.FE,toJSON:n.U2};window.dispatchEvent(new CustomEvent(S,{detail:i}))}emitPublishError(e,t,i){const s={channel:this.channel,selfPublish:e,seo:t??void 0,error:i};window.dispatchEvent(new CustomEvent(L,{detail:s}))}celebratePublish(e){const t=document.createElement("cdtr-publish-success");e&&(t.seoTitle=e.title,t.seoDescription=e.description);const i=this.siteUrl();i&&(t.url=i),document.body.appendChild(t)}render(){const e=!!o.M.get("config","access");if(!(this.onNextStep||"function"==typeof this.onPublish||"web"===this.channel&&e))return null;const t="web"===this.channel?"publish":"next";return s.qy`
759
+ <paper-button
760
+ @click=${this.onNextClick}
761
+ class="next-button"
762
+ ?disabled=${this.isLocked}
763
+ >
764
+ ${this.isLoading?s.qy`
765
+ <div class="loading-spinner"></div>
766
+ `:s.qy`
767
+ <div class="button-content ${this.isLoading?"loading":""}">
768
+ <lang-text text=${t}></lang-text>
769
+ </div>
770
+ `}
771
+ </paper-button>
772
+ `}}P.styles=s.AH`
773
+ :host {
774
+ display: block;
775
+ }
776
+
777
+ .next-button {
778
+ background: var(--primary);
779
+ color: var(--primary-text);
780
+ fill: var(--primary-text);
781
+ text-transform: none;
782
+ color: #fff;
783
+ height: 52px;
784
+ border-radius: 0;
785
+ width: 90px;
786
+ transform: translateX(-4px);
787
+ position: relative;
788
+ overflow: hidden;
789
+ }
790
+
791
+ .next-button:disabled {
792
+ opacity: 0.6;
793
+ cursor: not-allowed;
794
+ }
795
+
796
+ .loading-spinner {
797
+ position: absolute;
798
+ top: 50%;
799
+ left: 50%;
800
+ transform: translate(-50%, -50%);
801
+ width: 20px;
802
+ height: 20px;
803
+ border: 2px solid transparent;
804
+ border-top: 2px solid #fff;
805
+ border-radius: 50%;
806
+ animation: spin 1s linear infinite;
807
+ }
808
+
809
+ @keyframes spin {
810
+ 0% { transform: translate(-50%, -50%) rotate(0deg); }
811
+ 100% { transform: translate(-50%, -50%) rotate(360deg); }
812
+ }
813
+
814
+ .button-content {
815
+ opacity: 1;
816
+ transition: opacity 0.3s ease;
817
+ }
818
+
819
+ .button-content.loading {
820
+ opacity: 0;
821
+ }
822
+
823
+ `,P.properties={onNextStep:{type:Function},onPublish:{type:Function},channel:{type:String},isLoading:{type:Boolean},isLocked:{type:Boolean},lockTimer:{type:Number}},customElements.define("cdtr-next-button",P)}}]);