/* ==========================================================================
M GALA Admin — shared shell (sidebar, toast, avatar fallback, modal)
========================================================================== */
(function () {
"use strict";
var Store = window.MGala.Store;
var NAV = [
{ href: "index.html", label: "Dashboard", icon: "fa-house" },
{ href: "nominations.html", label: "Nominations", icon: "fa-clipboard-list" },
{ href: "nominees.html", label: "Nominees", icon: "fa-users" },
{ href: "categories.html", label: "Categories", icon: "fa-tags" },
{ href: "featured.html", label: "Featured Woman", icon: "fa-star" }
];
var PASSCODE = "mgala2026";
function isUnlocked() {
try { return sessionStorage.getItem("mgala_admin_ok") === "1"; } catch (e) { return false; }
}
function unlock() {
try { sessionStorage.setItem("mgala_admin_ok", "1"); } catch (e) {}
}
function renderLockScreen() {
var overlay = document.createElement("div");
overlay.id = "admin-lock-overlay";
overlay.innerHTML =
'
' +
'
' +
'
M GALA
' +
'
Admin Workspace
' +
'
Enter Passcode
' +
'
This area is private. Enter the admin passcode to continue.
' +
'
' +
'
← Back to public site' +
'
' +
'
';
document.body.appendChild(overlay);
var form = document.getElementById("lock-form");
var input = document.getElementById("lock-input");
var error = document.getElementById("lock-error");
form.addEventListener("submit", function (e) {
e.preventDefault();
if (input.value.trim() === PASSCODE) {
unlock();
location.reload();
} else {
error.classList.add("show");
input.value = "";
input.focus();
}
});
}
window.MGala.renderAdminShell = function (active) {
if (!isUnlocked()) { renderLockScreen(); return; }
var shell = document.querySelector(".admin-shell");
var mainContent = document.getElementById("admin-content");
var backdrop = document.createElement("div");
backdrop.className = "sidebar-backdrop";
backdrop.id = "sb-backdrop";
var aside = document.createElement("aside");
aside.className = "sidebar";
aside.id = "sidebar";
aside.innerHTML =
'M GALAAdmin Workspace
' +
'' +
'';
shell.insertBefore(aside, shell.firstChild);
shell.insertBefore(backdrop, shell.firstChild);
var contentCol = document.createElement("div");
contentCol.style.flex = "1";
contentCol.style.minWidth = "0";
shell.insertBefore(contentCol, mainContent);
var topbar = document.createElement("div");
topbar.className = "admin-topbar";
topbar.innerHTML =
'' +
'M GALA
' +
'';
contentCol.appendChild(topbar);
contentCol.appendChild(mainContent);
document.getElementById("sb-open").addEventListener("click", function () {
document.getElementById("sidebar").classList.add("open");
document.getElementById("sb-backdrop").classList.add("open");
});
document.getElementById("sb-backdrop").addEventListener("click", function () {
document.getElementById("sidebar").classList.remove("open");
document.getElementById("sb-backdrop").classList.remove("open");
});
};
/* ---------- avatar fallback ---------- */
function initialsAvatar(name) {
var initials = (name || "?").split(" ").filter(Boolean).slice(0, 2).map(function (s) { return s[0]; }).join("").toUpperCase();
var svg = '";
return "data:image/svg+xml;base64," + btoa(svg);
}
window.MGala.attachImgFallback = function (img, name) {
img.addEventListener("error", function onErr() {
img.removeEventListener("error", onErr);
img.src = initialsAvatar(name);
});
};
window.MGala.wireImgFallbacks = function (root) {
(root || document).querySelectorAll("img[data-name]").forEach(function (img) {
window.MGala.attachImgFallback(img, img.getAttribute("data-name"));
});
};
/* ---------- toast ---------- */
var toastTimer;
window.MGala.toast = function (msg, icon) {
var el = document.getElementById("mg-toast");
if (!el) {
el = document.createElement("div");
el.id = "mg-toast";
el.className = "toast";
document.body.appendChild(el);
}
el.innerHTML = '' + msg + "";
el.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () { el.classList.remove("show"); }, 3400);
};
window.MGala.timeAgoStr = function (h) { return Store.timeAgo(h); };
/* ---------- photo picker: upload (compressed) + silhouette swatches ---------- */
window.MGala.readAndCompressImage = function (file, maxWidth, callback) {
maxWidth = maxWidth || 700;
var reader = new FileReader();
reader.onload = function (e) {
var img = new Image();
img.onload = function () {
var scale = Math.min(1, maxWidth / img.width);
var w = Math.round(img.width * scale);
var h = Math.round(img.height * scale);
var canvas = document.createElement("canvas");
canvas.width = w;
canvas.height = h;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, w, h);
callback(canvas.toDataURL("image/jpeg", 0.82));
};
img.onerror = function () { window.MGala.toast("Could not read that image.", "fa-triangle-exclamation"); };
img.src = e.target.result;
};
reader.onerror = function () { window.MGala.toast("Could not read that file.", "fa-triangle-exclamation"); };
reader.readAsDataURL(file);
};
window.MGala.renderPhotoPicker = function (container, current) {
// current: { photo, photoStyle } — photoStyle is one of Store.SILHOUETTE_STYLES or null (real upload)
var state = { photo: current.photo, photoStyle: current.photoStyle || null };
container.innerHTML =
'' +
'
' +
'
' +
'
' +
'
or choose a placeholder
' +
'
' +
'
' +
'
';
var previewImg = container.querySelector("#pp-preview-img");
var swatchesEl = container.querySelector("#pp-swatches");
function renderSwatches() {
swatchesEl.innerHTML = Store.SILHOUETTE_STYLES.map(function (styleKey) {
var uri = Store.silhouetteUri(styleKey);
var sel = state.photoStyle === styleKey;
return '';
}).join("");
swatchesEl.querySelectorAll("[data-style]").forEach(function (btn) {
btn.addEventListener("click", function () {
var styleKey = btn.getAttribute("data-style");
state.photo = Store.silhouetteUri(styleKey);
state.photoStyle = styleKey;
previewImg.src = state.photo;
renderSwatches();
});
});
}
renderSwatches();
container.querySelector("#pp-file-input").addEventListener("change", function (e) {
var file = e.target.files && e.target.files[0];
if (!file) return;
window.MGala.readAndCompressImage(file, 700, function (dataUrl) {
state.photo = dataUrl;
state.photoStyle = null;
previewImg.src = dataUrl;
renderSwatches();
window.MGala.toast("Photo uploaded — remember to save.", "fa-image");
});
});
return { get: function () { return { photo: state.photo, photoStyle: state.photoStyle }; } };
};
})();