mvbhr's picture
nao consigo mover as janelas
5802eff verified
class AppWindow extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: 'open' });
const title = this.getAttribute('title') || 'Window';
const icon = this.getAttribute('icon') || 'square';
const width = this.getAttribute('width') || '600';
const height = this.getAttribute('height') || '400';
const x = this.getAttribute('x') || '100';
const y = this.getAttribute('y') || '100';
this.shadowRoot.innerHTML = `
<style>
:host {
position: absolute;
width: ${width}px;
height: ${height}px;
left: ${x}px;
top: ${y}px;
background: #18181b;
border: 1px solid #3f3f46;
border-radius: 8px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4);
display: flex;
flex-direction: column;
overflow: hidden;
transition: box-shadow 0.2s;
animation: windowEnter 0.2s ease-out;
}
:host(.active-window) {
box-shadow: 0 15px 50px rgba(0, 0, 0, 0.5);
}
.window-header {
display: flex;
align-items: center;
justify-content: space-between;
background: linear-gradient(to bottom, #27272a, #1f1f23);
border-bottom: 1px solid #3f3f46;
padding: 4px 8px;
cursor: move;
user-select: none;
}
.window-title {
display: flex;
align-items: center;
gap: 6px;
color: #e4e4e7;
font-size: 12px;
font-weight: 500;
}
.window-controls {
display: flex;
gap: 4px;
}
.window-control {
width: 16px;
height: 16px;
border-radius: 50%;
border: none;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
}
.window-control.minimize {
background: #fbbf24;
}
.window-control.maximize {
background: #34d399;
}
.window-control.close {
background: #ef4444;
}
.window-control:hover {
opacity: 0.8;
transform: scale(1.1);
}
.window-control i {
width: 8px;
height: 8px;
color: rgba(0, 0, 0, 0.7);
}
.window-content {
flex: 1;
overflow: auto;
background: #18181b;
}
.window-resize-handle {
position: absolute;
bottom: 0;
right: 0;
width: 16px;
height: 16px;
cursor: nwse-resize;
background: linear-gradient(135deg, transparent 50%, #3f3f46 50%);
border-bottom-right-radius: 8px;
}
@keyframes windowEnter {
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
}
</style>
<div class="window-header" id="window-header">
<div class="window-title">
<i data-feather="${icon}" style="width: 14px; height: 14px;"></i>
<span>${title}</span>
</div>
<div class="window-controls">
<button class="window-control minimize" title="Minimizar">
<i data-feather="minus"></i>
</button>
<button class="window-control maximize" title="Maximizar">
<i data-feather="square"></i>
</button>
<button class="window-control close" title="Fechar">
<i data-feather="x"></i>
</button>
</div>
</div>
<div class="window-content">
<slot></slot>
</div>
<div class="window-resize-handle" id="resize-handle"></div>
`;
this.windowId = this.id;
this.isDragging = false;
this.isResizing = false;
this.initializeEventListeners();
// Re-render feather icons
setTimeout(() => feather.replace(), 0);
// Focus the window initially
setTimeout(() => focusWindow(this.windowId), 100);
}
initializeEventListeners() {
const header = this.shadowRoot.getElementById('window-header');
const resizeHandle = this.shadowRoot.getElementById('resize-handle');
const minimizeBtn = this.shadowRoot.querySelector('.window-control.minimize');
const maximizeBtn = this.shadowRoot.querySelector('.window-control.maximize');
const closeBtn = this.shadowRoot.querySelector('.window-control.close');
// Window dragging
header.addEventListener('mousedown', (e) => {
if (e.target.closest('.window-controls')) return;
this.startDragging(e);
});
// Window resizing
resizeHandle.addEventListener('mousedown', (e) => {
this.startResizing(e);
});
// Window controls
minimizeBtn.addEventListener('click', () => {
minimizeWindow(this.windowId);
});
maximizeBtn.addEventListener('click', () => {
maximizeWindow(this.windowId);
});
closeBtn.addEventListener('click', () => {
closeWindow(this.windowId);
});
// Focus on click
this.addEventListener('mousedown', () => {
focusWindow(this.windowId);
});
// Global mouse events
document.addEventListener('mousemove', (e) => this.handleMouseMove(e));
document.addEventListener('mouseup', () => this.handleMouseUp());
}
startDragging(e) {
this.isDragging = true;
this.dragOffsetX = e.clientX - parseInt(this.style.left);
this.dragOffsetY = e.clientY - parseInt(this.style.top);
this.style.cursor = 'move';
}
startResizing(e) {
this.isResizing = true;
this.resizeStartX = e.clientX;
this.resizeStartY = e.clientY;
this.resizeStartWidth = parseInt(this.style.width);
this.resizeStartHeight = parseInt(this.style.height);
e.stopPropagation();
}
handleMouseMove(e) {
if (this.isDragging) {
const newX = Math.max(0, Math.min(e.clientX - this.dragOffsetX, window.innerWidth - parseInt(this.style.width || this.getAttribute('width'))));
const newY = Math.max(0, Math.min(e.clientY - this.dragOffsetY, window.innerHeight - parseInt(this.style.height || this.getAttribute('height')) - 32));
this.style.left = `${newX}px`;
this.style.top = `${newY}px`;
} else if (this.isResizing) {
const deltaX = e.clientX - this.resizeStartX;
const deltaY = e.clientY - this.resizeStartY;
const newWidth = Math.max(300, this.resizeStartWidth + deltaX);
const newHeight = Math.max(200, this.resizeStartHeight + deltaY);
this.style.width = `${newWidth}px`;
this.style.height = `${newHeight}px`;
}
}
handleMouseUp() {
this.isDragging = false;
this.isResizing = false;
this.style.cursor = '';
}
}
customElements.define('app-window', AppWindow);