ngx-xtroedge-cms 1.3.2 → 1.3.4
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.
- package/dist/index.d.mts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.global.js +76 -3
- package/dist/index.js +152 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +152 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -237,6 +237,58 @@ var CMS_STYLES = `
|
|
|
237
237
|
}
|
|
238
238
|
.lcms-spinner-lg { width: 36px; height: 36px; border: 3px solid rgba(255,255,255,0.2); border-top-color: var(--lcms-primary, #00C853); border-radius: 50%; animation: lcmsSpin 0.6s linear infinite; }
|
|
239
239
|
|
|
240
|
+
/* LOGIN MODAL */
|
|
241
|
+
.lcms-login-overlay {
|
|
242
|
+
position: fixed; inset: 0; z-index: 10010;
|
|
243
|
+
display: flex; align-items: center; justify-content: center;
|
|
244
|
+
background: rgba(8, 8, 15, 0.75);
|
|
245
|
+
backdrop-filter: blur(16px) saturate(1.4);
|
|
246
|
+
-webkit-backdrop-filter: blur(16px) saturate(1.4);
|
|
247
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
248
|
+
}
|
|
249
|
+
.lcms-login-box {
|
|
250
|
+
background: #13151a; border: 1px solid rgba(255,255,255,0.1);
|
|
251
|
+
border-radius: 16px; padding: 36px 32px; width: 340px;
|
|
252
|
+
box-shadow: 0 24px 60px rgba(0,0,0,0.6);
|
|
253
|
+
}
|
|
254
|
+
.lcms-login-logo {
|
|
255
|
+
display: flex; align-items: center; justify-content: center;
|
|
256
|
+
gap: 8px; margin-bottom: 24px;
|
|
257
|
+
}
|
|
258
|
+
.lcms-login-logo-icon {
|
|
259
|
+
width: 32px; height: 32px; border-radius: 8px;
|
|
260
|
+
background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32));
|
|
261
|
+
display: flex; align-items: center; justify-content: center;
|
|
262
|
+
}
|
|
263
|
+
.lcms-login-logo-text { color: white; font-size: 15px; font-weight: 700; letter-spacing: 0.5px; }
|
|
264
|
+
.lcms-login-title { color: white; font-size: 18px; font-weight: 700; text-align: center; margin-bottom: 6px; }
|
|
265
|
+
.lcms-login-sub { color: rgba(255,255,255,0.4); font-size: 12px; text-align: center; margin-bottom: 24px; }
|
|
266
|
+
.lcms-login-field { margin-bottom: 14px; }
|
|
267
|
+
.lcms-login-label { display: block; color: rgba(255,255,255,0.6); font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.8px; margin-bottom: 6px; }
|
|
268
|
+
.lcms-login-input {
|
|
269
|
+
width: 100%; box-sizing: border-box;
|
|
270
|
+
background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.12);
|
|
271
|
+
border-radius: 8px; padding: 10px 12px;
|
|
272
|
+
color: white; font-size: 13px; font-family: inherit; outline: none;
|
|
273
|
+
transition: border-color 0.2s;
|
|
274
|
+
}
|
|
275
|
+
.lcms-login-input:focus { border-color: var(--lcms-primary, #00C853); }
|
|
276
|
+
.lcms-login-input::placeholder { color: rgba(255,255,255,0.25); }
|
|
277
|
+
.lcms-login-btn {
|
|
278
|
+
width: 100%; padding: 11px; margin-top: 6px; border: none; border-radius: 8px; cursor: pointer;
|
|
279
|
+
background: linear-gradient(135deg, var(--lcms-primary, #00C853), var(--lcms-primary-dark, #2E7D32));
|
|
280
|
+
color: white; font-size: 13px; font-weight: 700; font-family: inherit;
|
|
281
|
+
letter-spacing: 0.3px; transition: filter 0.2s;
|
|
282
|
+
}
|
|
283
|
+
.lcms-login-btn:hover { filter: brightness(1.1); }
|
|
284
|
+
.lcms-login-btn:disabled { opacity: 0.6; cursor: not-allowed; }
|
|
285
|
+
.lcms-login-error {
|
|
286
|
+
background: rgba(239,68,68,0.15); border: 1px solid rgba(239,68,68,0.3);
|
|
287
|
+
border-radius: 8px; padding: 9px 12px; color: #f87171;
|
|
288
|
+
font-size: 12px; text-align: center; margin-top: 12px; display: none;
|
|
289
|
+
}
|
|
290
|
+
.lcms-login-error.visible { display: block; }
|
|
291
|
+
|
|
240
292
|
/* HIDDEN ELEMENTS */
|
|
241
293
|
.lcms-hidden { display: none !important; }
|
|
242
294
|
`;
|
|
@@ -286,6 +338,9 @@ var XtroedgeCMS = class _XtroedgeCMS {
|
|
|
286
338
|
this.brandingEl = null;
|
|
287
339
|
this.siteIdentifier = "";
|
|
288
340
|
this.siteIdEl = null;
|
|
341
|
+
this.loginModalEl = null;
|
|
342
|
+
this.pendingEditMode = false;
|
|
343
|
+
// edit=true was requested but token missing
|
|
289
344
|
// ===== State =====
|
|
290
345
|
this.editMode = false;
|
|
291
346
|
this.currentLang = "en";
|
|
@@ -475,12 +530,24 @@ var XtroedgeCMS = class _XtroedgeCMS {
|
|
|
475
530
|
this.resetAll();
|
|
476
531
|
}
|
|
477
532
|
const editFromSession = sessionStorage.getItem("builder_edit_mode") === "true";
|
|
478
|
-
|
|
533
|
+
const wantsEdit = editViaParam || editFromSession;
|
|
534
|
+
if (wantsEdit) {
|
|
535
|
+
const token = localStorage.getItem("builder_token");
|
|
536
|
+
if (!token) {
|
|
537
|
+
this.pendingEditMode = true;
|
|
538
|
+
this.currentLang = this.detectCurrentLanguage();
|
|
539
|
+
this.setLoading(true);
|
|
540
|
+
setTimeout(() => {
|
|
541
|
+
this.loadTranslationsAndInit(false);
|
|
542
|
+
this.showLoginModal();
|
|
543
|
+
}, 300);
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
479
546
|
this.editMode = true;
|
|
480
547
|
}
|
|
481
548
|
this.currentLang = this.detectCurrentLanguage();
|
|
482
549
|
this.setLoading(true);
|
|
483
|
-
const loadDraft =
|
|
550
|
+
const loadDraft = wantsEdit;
|
|
484
551
|
setTimeout(() => {
|
|
485
552
|
this.loadTranslationsAndInit(loadDraft);
|
|
486
553
|
}, 300);
|
|
@@ -1691,6 +1758,89 @@ var XtroedgeCMS = class _XtroedgeCMS {
|
|
|
1691
1758
|
return `${months[d.getMonth()]} ${d.getDate()}, ${h12}:${m} ${ampm}`;
|
|
1692
1759
|
}
|
|
1693
1760
|
// ===============================================
|
|
1761
|
+
// LOGIN MODAL
|
|
1762
|
+
// ===============================================
|
|
1763
|
+
showLoginModal() {
|
|
1764
|
+
if (this.loginModalEl) return;
|
|
1765
|
+
const overlay = document.createElement("div");
|
|
1766
|
+
overlay.className = "lcms-login-overlay";
|
|
1767
|
+
overlay.id = "lcms-login-modal";
|
|
1768
|
+
overlay.innerHTML = `
|
|
1769
|
+
<div class="lcms-login-box">
|
|
1770
|
+
<div class="lcms-login-logo">
|
|
1771
|
+
<div class="lcms-login-logo-icon">
|
|
1772
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
|
|
1773
|
+
</div>
|
|
1774
|
+
<span class="lcms-login-logo-text">XtroEdge CMS</span>
|
|
1775
|
+
</div>
|
|
1776
|
+
<div class="lcms-login-title">Builder Login</div>
|
|
1777
|
+
<div class="lcms-login-sub">Sign in to access edit mode</div>
|
|
1778
|
+
<div class="lcms-login-field">
|
|
1779
|
+
<label class="lcms-login-label">Username</label>
|
|
1780
|
+
<input class="lcms-login-input" id="lcms-login-email" type="text" placeholder="Enter your username" autocomplete="username" />
|
|
1781
|
+
</div>
|
|
1782
|
+
<div class="lcms-login-field">
|
|
1783
|
+
<label class="lcms-login-label">Password</label>
|
|
1784
|
+
<input class="lcms-login-input" id="lcms-login-password" type="password" placeholder="Enter your password" autocomplete="current-password" />
|
|
1785
|
+
</div>
|
|
1786
|
+
<button class="lcms-login-btn" id="lcms-login-btn">Sign In</button>
|
|
1787
|
+
<div class="lcms-login-error" id="lcms-login-error"></div>
|
|
1788
|
+
</div>
|
|
1789
|
+
`;
|
|
1790
|
+
document.body.appendChild(overlay);
|
|
1791
|
+
this.loginModalEl = overlay;
|
|
1792
|
+
const btn = overlay.querySelector("#lcms-login-btn");
|
|
1793
|
+
const emailInput = overlay.querySelector("#lcms-login-email");
|
|
1794
|
+
const passInput = overlay.querySelector("#lcms-login-password");
|
|
1795
|
+
const doLogin = () => this.attemptLogin(emailInput.value.trim(), passInput.value);
|
|
1796
|
+
btn.addEventListener("click", doLogin);
|
|
1797
|
+
passInput.addEventListener("keydown", (e) => {
|
|
1798
|
+
if (e.key === "Enter") doLogin();
|
|
1799
|
+
});
|
|
1800
|
+
setTimeout(() => emailInput.focus(), 50);
|
|
1801
|
+
}
|
|
1802
|
+
hideLoginModal() {
|
|
1803
|
+
this.loginModalEl?.remove();
|
|
1804
|
+
this.loginModalEl = null;
|
|
1805
|
+
}
|
|
1806
|
+
async attemptLogin(email, password) {
|
|
1807
|
+
const btn = document.getElementById("lcms-login-btn");
|
|
1808
|
+
const errorEl = document.getElementById("lcms-login-error");
|
|
1809
|
+
if (!email || !password) {
|
|
1810
|
+
errorEl.textContent = "Please enter your username and password.";
|
|
1811
|
+
errorEl.classList.add("visible");
|
|
1812
|
+
return;
|
|
1813
|
+
}
|
|
1814
|
+
btn.disabled = true;
|
|
1815
|
+
btn.textContent = "Signing in...";
|
|
1816
|
+
errorEl.classList.remove("visible");
|
|
1817
|
+
try {
|
|
1818
|
+
const loginUrl = this.config.loginUrl || `${this.config.apiBase}/auth/login`;
|
|
1819
|
+
const res = await fetch(loginUrl, {
|
|
1820
|
+
method: "POST",
|
|
1821
|
+
headers: { "Content-Type": "application/json" },
|
|
1822
|
+
body: JSON.stringify({ username: email, password })
|
|
1823
|
+
});
|
|
1824
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
1825
|
+
const data = await res.json();
|
|
1826
|
+
const token = data?.token || data?.authToken || data?.auth_token || data?.data?.token;
|
|
1827
|
+
if (!token) throw new Error("No token in response");
|
|
1828
|
+
localStorage.setItem("builder_token", token);
|
|
1829
|
+
this.hideLoginModal();
|
|
1830
|
+
this.editMode = true;
|
|
1831
|
+
this.pendingEditMode = false;
|
|
1832
|
+
sessionStorage.setItem("builder_edit_mode", "true");
|
|
1833
|
+
this.applyEditMode(true);
|
|
1834
|
+
this.updateUI();
|
|
1835
|
+
this.loadPageContent("draft");
|
|
1836
|
+
} catch {
|
|
1837
|
+
btn.disabled = false;
|
|
1838
|
+
btn.textContent = "Sign In";
|
|
1839
|
+
errorEl.textContent = "Invalid credentials. Please try again.";
|
|
1840
|
+
errorEl.classList.add("visible");
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
// ===============================================
|
|
1694
1844
|
// SITE IDENTIFIER
|
|
1695
1845
|
// ===============================================
|
|
1696
1846
|
resolveSiteIdentifier() {
|