gets a Phone rendered
inside a 390x812 scaler that is CSS-scaled to the stage's width.
Phones follow the site's data-theme (dark/light) live. */
(function () {
const SCREENS = {
store: () =>
,
slots: () =>
,
dashboard: () =>
,
brief: () =>
,
confirmed: () =>
,
};
const theme = () =>
document.documentElement.getAttribute("data-theme") === "light" ? "light" : "dark";
const PHONE_W = 390, PHONE_H = 812;
const mounts = [];
// Size each phone entirely from JS so it never depends on (possibly stale)
// CSS: the stage gets an explicit width/height and the inner 390x812 scaler
// is transform-scaled to match. Target widths come from data-w (desktop) /
// data-wm (narrow), and are always capped to the viewport.
function fit(m) {
const vw = window.innerWidth;
const narrow = vw < 860;
let w = narrow
? (+m.stage.dataset.wm || +m.stage.dataset.w || 240)
: (+m.stage.dataset.w || 240);
w = Math.min(w, vw - 48);
const h = Math.round((w * PHONE_H) / PHONE_W);
m.stage.style.width = w + "px";
m.stage.style.height = h + "px";
m.scaler.style.transform = "scale(" + w / PHONE_W + ")";
}
function render(m) {
m.root.render(
{m.make()});
}
function mountAll() {
document.querySelectorAll(".app-stage[data-mock]").forEach((stage) => {
const make = SCREENS[stage.getAttribute("data-mock")];
if (!make || stage.dataset._mounted) return;
stage.dataset._mounted = "1";
const scaler = document.createElement("div");
scaler.className = "jk-scaler";
stage.appendChild(scaler);
const m = { stage, scaler, make, root: ReactDOM.createRoot(scaler) };
mounts.push(m);
render(m);
fit(m);
});
window.addEventListener("resize", () => mounts.forEach(fit));
}
// Re-render every phone when the site theme flips.
new MutationObserver(() => mounts.forEach(render)).observe(
document.documentElement,
{ attributes: true, attributeFilter: ["data-theme"] }
);
if (document.readyState === "loading")
document.addEventListener("DOMContentLoaded", mountAll);
else mountAll();
})();