function windowBox(id, initialX = 50, initialY = 50) { // Load saved data or user defaults const saved = JSON.parse(localStorage.getItem(`win_${id}`)) || { x: initialX, y: initialY, min: false, }; return { id: id, pos: { x: saved.x, y: saved.y }, lastPos: { x: saved.x, y: saved.y }, dragging: false, minimized: saved.min, fullscreen: false, zIndex: Alpine.store("ui").topZ, offset: { x: 0, y: 0 }, init() { // Move window in viewport when browser is other size this.keepInBounds(); }, focus() { this.zIndex = Alpine.store("ui").getNewZ(); }, startDrag(e) { if (e.target.closest("button") || this.fullscreen) return; this.focus(); this.dragging = true; this.offset.x = e.clientX - this.pos.x; this.offset.y = e.clientY - this.pos.y; }, onDrag(e) { if (!this.dragging) return; // Calc new position let newX = e.clientX - this.offset.x; let newY = e.clientY - this.offset.y; // Boundary Check const margin = 20; this.pos.x = Math.max( margin - 350, Math.min(newX, window.innerWidth - 50), ); this.pos.y = Math.max(0, Math.min(newY, window.innerHeight - 40)); }, stopDrag() { this.dragging = false; this.save(); }, keepInBounds() { if (this.pos.x > window.innerWidth) this.pos.x = window.innerWidth - 400; if (this.pos.y > window.innerHeight) this.pos.y = 50; }, save() { localStorage.setItem( `win_${this.id}`, JSON.stringify({ x: this.pos.x, y: this.pos.y, min: this.minimized, }), ); }, reset() { localStorage.removeItem(`win_${this.id}`); location.reload(); }, toggleMinimize() { this.minimized = !this.minimized; this.save(); }, toggleFullscreen() { if (!this.fullscreen) { this.lastPos = { ...this.pos }; // Save Position this.pos = { x: 0, y: 0 }; this.fullscreen = true; } else { this.pos = { ...this.lastPos }; // Back to old Position this.fullscreen = false; } this.focus(); }, }; }