154 lines
4.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// windows.js
document.addEventListener("alpine:init", () => {
// 1. Globaler Store for Window Managment
Alpine.store("Yet_WM", {
topZ: 1000,
getNewZ() {
return ++this.topZ;
},
});
Alpine.data("YetWindow", (id, initialX = 50, initialY = 50) => ({
id: id,
pos: { x: parseInt(initialX), y: parseInt(initialY) },
lastPos: { x: 0, y: 0 },
dragging: false,
minimized: false,
fullscreen: false,
zIndex: 1000,
offset: { x: 0, y: 0 },
init() {
// Lade gespeicherten Zustand (einheitlicher Key: yet_win_)
const saved = JSON.parse(localStorage.getItem(`yet_win_${this.id}`));
if (saved) {
this.pos = { x: saved.x, y: saved.y };
this.minimized = saved.min;
}
this.focus();
this.keepInBounds();
},
focus() {
this.zIndex = Alpine.store("Yet_WM").getNewZ();
},
startDrag(e) {
if (e.target.closest("button") || this.fullscreen) return;
// Verhindert Text-Markierung während des Verschiebens
e.preventDefault();
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;
let newX = e.clientX - this.offset.x;
let newY = e.clientY - this.offset.y;
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() {
if (this.dragging) {
this.dragging = false;
this.save();
}
},
toggleMinimize() {
this.minimized = !this.minimized;
this.save();
},
toggleFullscreen() {
if (!this.fullscreen) {
this.lastPos = { ...this.pos };
this.pos = { x: 0, y: 0 };
this.fullscreen = true;
} else {
this.pos = { ...this.lastPos };
this.fullscreen = false;
}
this.focus();
},
save() {
localStorage.setItem(
`yet_win_${this.id}`,
JSON.stringify({
x: this.pos.x,
y: this.pos.y,
min: this.minimized,
})
);
},
keepInBounds() {
if (this.pos.x > window.innerWidth) this.pos.x = 50;
if (this.pos.y > window.innerHeight) this.pos.y = 50;
},
}));
});
// Definition der Web Component
class YetWindowElement extends HTMLElement {
connectedCallback() {
const id = this.getAttribute("id") || "win_" + Math.random().toString(36).substr(2, 9);
const title = this.getAttribute("title") || "Window";
const x = this.getAttribute("x") || "50";
const y = this.getAttribute("y") || "50";
const width = this.getAttribute("width") || "450px";
const headerClass = this.getAttribute("header-class") || "bg-dark text-white";
const content = this.innerHTML;
this.innerHTML = `
<div
x-data="YetWindow('${id}', ${x}, ${y})"
@mousemove.window="onDrag"
@mouseup.window="stopDrag"
@mousedown="focus"
class="card shadow-lg position-absolute"
:class="{ 'w-100 h-100 m-0 shadow-none': fullscreen }"
:style="\`left: \${pos.x}px; top: \${pos.y}px; z-index: \${zIndex}; width: \${fullscreen ? '100vw' : '${width}'}; user-select: \${dragging ? 'none' : 'auto'};\`"
x-cloak
>
<div
class="card-header d-flex justify-content-between align-items-center drag-handle ${headerClass}"
@mousedown="startDrag"
@dblclick="toggleFullscreen"
style="user-select: none;"
>
<h6 class="mb-0">${title}</h6>
<div class="d-flex align-items-center gap-1">
<button class="btn btn-sm btn-outline-light py-0 px-2" @click="toggleFullscreen">
<span>▢</span>
</button>
<button class="btn btn-sm btn-outline-light py-0 px-2" @click="toggleMinimize">
<span x-text="minimized ? '+' : ''"></span>
</button>
</div>
</div>
<div x-show="!minimized" class="flex-grow-1 overflow-auto">
<div class="card-body">
${content}
</div>
</div>
</div>
`;
}
}
customElements.define("yet-window", YetWindowElement);