function waitForElm(selector) {
return new Promise((resolve) => {
if (document.querySelector(selector)) {
return resolve(document.querySelector(selector));
}
const observer = new MutationObserver((mutations) => {
if (document.querySelector(selector)) {
observer.disconnect();
resolve(document.querySelector(selector));
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
});
}
(() => {
const setup = () => {
const tauri = window.__TAURI__;
if (!tauri) {
console.log("DECORATION: Tauri API not found. Exiting.");
console.log(
"DECORATION: Set withGlobalTauri: true in tauri.conf.json to enable.",
);
return;
}
const win = tauri.window.getCurrentWindow();
console.log("DECORATION: Waiting for [data-tauri-decoration-tb] ...");
const debounce = (func, delay) => {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func(...args), delay);
};
};
const BUTTON_HOVER_BG_LIGHT = "rgba(0,0,0,0.1)";
const BUTTON_HOVER_BG_DARK = "rgba(255,255,255,0.1)";
const CLOSE_HOVER_BG = "rgba(255,0,0,0.7)";
const getButtonHoverBg = () =>
window.matchMedia("(prefers-color-scheme: dark)").matches
? BUTTON_HOVER_BG_DARK
: BUTTON_HOVER_BG_LIGHT;
let activeControl = null;
const buttons = new Map();
const renderHover = () => {
const hoverBg = getButtonHoverBg();
buttons.forEach(({ button, isClose }, control) => {
button.style.backgroundColor =
control === activeControl
? isClose
? CLOSE_HOVER_BG
: hoverBg
: "transparent";
});
};
const setActiveControl = (control) => {
activeControl = control;
renderHover();
};
const hitTestControls = (x, y) => {
const element = document.elementFromPoint(x, y);
const button = element?.closest?.("[id^='decoration-tb-']");
setActiveControl(
button ? button.id.slice("decoration-tb-".length) : null,
);
};
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
renderHover();
});
const createButton = (id) => {
const btn = document.createElement("button");
btn.id = "decoration-tb-" + id;
btn.style.width = "58px";
btn.style.height = "32px";
btn.style.border = "none";
btn.style.padding = "0px";
btn.style.outline = "none";
btn.style.display = "flex";
btn.style.fontSize = "10px";
btn.style.fontWeight = "300";
btn.style.cursor = "default";
btn.style.boxShadow = "none";
btn.style.borderRadius = "0px";
btn.style.alignItems = "center";
btn.style.justifyContent = "center";
btn.style.transition = "background 0.1s";
btn.style.backgroundColor = "transparent";
btn.style.textRendering = "optimizeLegibility";
btn.style.fontFamily = "'Segoe Fluent Icons', 'Segoe MDL2 Assets'";
const isClose = id === "close";
const setHover = (hovered) => {
if (hovered) {
setActiveControl(id);
} else if (activeControl === id) {
setActiveControl(null);
}
};
const state = {
actionLock: false,
lastAction: 0,
};
const tryAction = (action) => {
const now = Date.now();
if (state.actionLock || now - state.lastAction < 200) return;
state.actionLock = true;
state.lastAction = now;
setHover(false);
Promise.resolve(action()).finally(() => {
setTimeout(() => { state.actionLock = false; }, 100);
});
};
buttons.set(id, { button: btn, isClose });
btn.onmouseenter = () => setHover(true);
btn.onmouseleave = () => setHover(false);
switch (id) {
case "minimize":
btn.innerHTML = "\uE921";
btn.setAttribute("aria-label", "Minimize window");
btn.onclick = (e) => {
e.preventDefault();
tryAction(() => win.minimize());
};
break;
case "maximize":
btn.innerHTML = "\uE922";
btn.setAttribute("aria-label", "Maximize window");
const toggleMaximize = (e) => {
if (e) e.preventDefault();
tryAction(() => win.toggleMaximize());
};
btn.onclick = toggleMaximize;
win.listen("decoration://snap/mousemove", ({ payload }) => {
if (Array.isArray(payload)) hitTestControls(payload[0], payload[1]);
});
win.listen("decoration://snap/mouseenter", () => setHover(true));
win.listen("decoration://snap/mouseleave", () => setHover(false));
win.listen("decoration://snap/mousedown", () => setHover(true));
win.listen("decoration://snap/mouseup", () => setHover(true));
win.listen("decoration://snap/click", () => toggleMaximize());
win.onResized(() => {
win.isMaximized().then((maximized) => {
if (maximized) {
btn.innerHTML = "\uE923";
btn.setAttribute("aria-label", "Restore window size");
} else {
btn.innerHTML = "\uE922";
btn.setAttribute("aria-label", "Maximize window size");
}
});
});
break;
case "close":
btn.innerHTML = "\uE8BB";
btn.setAttribute("aria-label", "Close window");
btn.onclick = () => win.close();
break;
}
return btn;
};
const debouncedCreateControls = debounce(() => {
const tbEl = document.querySelector("[data-tauri-decoration-tb]");
if (!tbEl) return;
if (tbEl.querySelector("[id^='decoration-tb-']")) {
console.log("DECORATION: Controls already exist. Skipping creation.");
return;
}
["minimize", "maximize", "close"].forEach((id) => {
const btn = createButton(id);
tbEl.appendChild(btn);
});
});
const observer = new MutationObserver((mutations) => {
for (let mutation of mutations) {
if (mutation.type === "childList") {
const tbEl = document.querySelector("[data-tauri-decoration-tb]");
if (tbEl) {
debouncedCreateControls();
break;
}
}
}
});
if (document.querySelector("[data-tauri-decoration-tb]")) {
debouncedCreateControls();
return;
}
observer.observe(document.body, {
childList: true,
subtree: true,
});
debouncedCreateControls();
};
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", setup);
} else {
setup();
}
})();