113 lines
3.4 KiB
JavaScript
113 lines
3.4 KiB
JavaScript
export const WindowManager = (function () {
|
|
let zIndexCounter = 9999990;
|
|
|
|
function makeDraggable(el, header) {
|
|
let isDragging = false, offX = 0, offY = 0;
|
|
|
|
header.addEventListener('mousedown', (e) => {
|
|
isDragging = true;
|
|
offX = e.clientX - el.offsetLeft;
|
|
offY = e.clientY - el.offsetTop;
|
|
|
|
// Bring to front
|
|
zIndexCounter++;
|
|
el.style.zIndex = zIndexCounter;
|
|
});
|
|
|
|
window.addEventListener('mousemove', (e) => {
|
|
if (isDragging) {
|
|
el.style.left = (e.clientX - offX) + 'px';
|
|
el.style.top = (e.clientY - offY) + 'px';
|
|
}
|
|
});
|
|
|
|
window.addEventListener('mouseup', () => isDragging = false);
|
|
}
|
|
|
|
function createWindow(id, title, props = {}) {
|
|
let win = document.getElementById(id);
|
|
if (win) {
|
|
// Just bring to front if exists
|
|
zIndexCounter++;
|
|
win.style.zIndex = zIndexCounter;
|
|
return { win, content: document.getElementById(id + '-content') };
|
|
}
|
|
|
|
const x = props.x || 100;
|
|
const y = props.y || 100;
|
|
const w = props.width || 300;
|
|
const h = props.height || 200;
|
|
|
|
win = document.createElement('div');
|
|
win.id = id;
|
|
win.style.cssText = `
|
|
position: fixed;
|
|
top: ${y}px;
|
|
left: ${x}px;
|
|
width: ${w}px;
|
|
height: ${h}px;
|
|
background: rgba(10, 10, 20, 0.95);
|
|
border: 1px solid #444;
|
|
border-radius: 8px;
|
|
z-index: ${++zIndexCounter};
|
|
display: flex;
|
|
flex-direction: column;
|
|
box-shadow: 0 4px 20px rgba(0,0,0,0.6);
|
|
font-family: sans-serif;
|
|
color: #eee;
|
|
backdrop-filter: blur(5px);
|
|
resize: both;
|
|
overflow: hidden;
|
|
`;
|
|
|
|
const header = document.createElement('div');
|
|
header.id = id + '-header';
|
|
header.style.cssText = `
|
|
padding: 8px;
|
|
background: rgba(255,255,255,0.05);
|
|
border-bottom: 1px solid #444;
|
|
cursor: move;
|
|
font-weight: bold;
|
|
font-size: 12px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
`;
|
|
|
|
const titleSpan = document.createElement('span');
|
|
titleSpan.textContent = title;
|
|
|
|
const closeBtn = document.createElement('span');
|
|
closeBtn.textContent = '✕';
|
|
closeBtn.style.cssText = 'cursor: pointer; color: #ff5252; font-size: 14px;';
|
|
closeBtn.onclick = () => win.remove();
|
|
|
|
header.appendChild(titleSpan);
|
|
header.appendChild(closeBtn);
|
|
|
|
const content = document.createElement('div');
|
|
content.id = id + '-content';
|
|
content.style.cssText = 'flex: 1; overflow-y: auto; padding: 10px;';
|
|
|
|
win.appendChild(header);
|
|
win.appendChild(content);
|
|
document.body.appendChild(win);
|
|
|
|
makeDraggable(win, header);
|
|
|
|
// Allow clicking anywhere on window to bring to front
|
|
win.addEventListener('mousedown', () => {
|
|
if (win.style.zIndex != zIndexCounter) {
|
|
zIndexCounter++;
|
|
win.style.zIndex = zIndexCounter;
|
|
}
|
|
});
|
|
|
|
return { win, content };
|
|
}
|
|
|
|
return {
|
|
create: createWindow
|
|
};
|
|
})();
|