ddsfsf
All checks were successful
Deploy / deploy-staging (push) Successful in 9s
Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-06-07 00:59:00 +02:00
parent e1d16d818d
commit 7a217022a6
3 changed files with 144 additions and 29 deletions

View File

@@ -149,7 +149,7 @@ Phase 3 Fenster-Manager:
- `ERLEDIGT`: Fenster oeffnen und schliessen
- `ERLEDIGT`: Fenster fokussieren
- `ERLEDIGT`: Fenster minimieren
- `TEILWEISE`: Fenster maximieren
- `ERLEDIGT`: Fenster maximieren
- `ERLEDIGT`: z-index-Verwaltung
- `OFFEN`: Position und Groesse merken
@@ -237,6 +237,7 @@ Vorhanden:
- Skin-Resolver
- Default-Workspace- und Widget-State
- einfacher Window-Manager
- Window-Controls fuer minimieren, maximieren und schliessen
- CSS/JS fuer Shell, Fenster, Taskbar, Startmenue, Widgets und Uhr
Hauptdateien:

View File

@@ -223,6 +223,10 @@ h1 {
display: none;
}
.window.is-maximized .window-header {
cursor: default;
}
.window-header {
display: flex;
justify-content: space-between;
@@ -291,6 +295,15 @@ h1 {
cursor: pointer;
}
.taskbar-app-button.is-focused {
background: var(--accent);
color: #0f172a;
}
.taskbar-app-button.is-minimized {
opacity: 0.62;
}
.start-menu {
position: absolute;
left: 24px;

View File

@@ -38,9 +38,12 @@ if (payloadNode) {
return;
}
record.state.minimized = false;
record.node.classList.remove('is-minimized');
zIndex += 1;
record.node.style.zIndex = String(zIndex);
record.node.classList.add('is-focused');
syncTaskbar();
};
const closeStartMenu = () => {
@@ -52,16 +55,91 @@ if (payloadNode) {
startButton?.setAttribute('aria-expanded', 'false');
};
const applyWindowLayout = (record) => {
const { x, y, width, height } = record.layout;
record.node.style.left = `${x}px`;
record.node.style.top = `${y}px`;
record.node.style.width = `${width}px`;
record.node.style.height = `${height}px`;
};
const toggleMinimize = (windowId) => {
const record = windows.get(windowId);
if (!record) {
return;
}
record.state.minimized = !record.state.minimized;
record.node.classList.toggle('is-minimized', record.state.minimized);
if (!record.state.minimized) {
focusWindow(windowId);
} else {
syncTaskbar();
}
};
const toggleMaximize = (windowId) => {
const record = windows.get(windowId);
if (!record) {
return;
}
if (!record.state.maximized) {
record.restoreLayout = { ...record.layout };
record.state.maximized = true;
record.node.classList.add('is-maximized');
record.node.style.left = '24px';
record.node.style.top = '24px';
record.node.style.width = 'calc(100% - 48px)';
record.node.style.height = 'calc(100% - 48px)';
focusWindow(windowId);
return;
}
record.state.maximized = false;
record.node.classList.remove('is-maximized');
if (record.restoreLayout) {
record.layout = { ...record.restoreLayout };
applyWindowLayout(record);
}
focusWindow(windowId);
};
const closeWindow = (windowId) => {
const record = windows.get(windowId);
if (!record) {
return;
}
windows.delete(windowId);
record.node.remove();
syncTaskbar();
};
const syncTaskbar = () => {
if (!taskbarRoot) {
return;
}
taskbarRoot.innerHTML = '';
windows.forEach((record) => {
const button = document.createElement('button');
button.type = 'button';
button.className = 'taskbar-app-button';
if (record.state.minimized) {
button.classList.add('is-minimized');
} else if (record.node.classList.contains('is-focused')) {
button.classList.add('is-focused');
}
button.textContent = record.title;
button.addEventListener('click', () => {
record.node.classList.toggle('is-minimized');
if (record.state.minimized) {
toggleMinimize(record.id);
return;
}
focusWindow(record.id);
});
taskbarRoot.appendChild(button);
@@ -81,11 +159,19 @@ if (payloadNode) {
let dragging = false;
header.addEventListener('pointerdown', (event) => {
if (record.state.maximized) {
return;
}
if (event.target instanceof Element && event.target.closest('.window-action')) {
return;
}
dragging = true;
startX = event.clientX;
startY = event.clientY;
originX = parseInt(record.node.style.left, 10);
originY = parseInt(record.node.style.top, 10);
originX = record.layout.x;
originY = record.layout.y;
header.setPointerCapture(event.pointerId);
focusWindow(record.id);
});
@@ -95,8 +181,9 @@ if (payloadNode) {
return;
}
record.node.style.left = `${originX + event.clientX - startX}px`;
record.node.style.top = `${originY + event.clientY - startY}px`;
record.layout.x = originX + event.clientX - startX;
record.layout.y = originY + event.clientY - startY;
applyWindowLayout(record);
});
header.addEventListener('pointerup', () => {
@@ -107,10 +194,6 @@ if (payloadNode) {
const createWindow = (definition) => {
const node = document.createElement('article');
node.className = 'window';
node.style.left = `${definition.x}px`;
node.style.top = `${definition.y}px`;
node.style.width = `${definition.width}px`;
node.style.height = `${definition.height}px`;
node.innerHTML = `
<header class="window-header">
<strong>${definition.title}</strong>
@@ -131,48 +214,54 @@ if (payloadNode) {
title: definition.title,
node,
definition,
layout: {
x: definition.x,
y: definition.y,
width: definition.width,
height: definition.height,
},
restoreLayout: null,
state: {
minimized: false,
maximized: false,
},
};
applyWindowLayout(record);
node.addEventListener('mousedown', () => focusWindow(record.id));
node.querySelectorAll('.window-action').forEach((action) => {
action.addEventListener('click', () => {
action.addEventListener('click', (event) => {
event.stopPropagation();
const actionName = action.dataset.action;
if (actionName === 'close') {
windows.delete(record.id);
node.remove();
syncTaskbar();
closeWindow(record.id);
return;
}
if (actionName === 'minimize') {
node.classList.toggle('is-minimized');
syncTaskbar();
toggleMinimize(record.id);
return;
}
if (actionName === 'maximize') {
node.style.left = '24px';
node.style.top = '24px';
node.style.width = 'calc(100% - 48px)';
node.style.height = 'calc(100% - 48px)';
focusWindow(record.id);
toggleMaximize(record.id);
}
});
});
windows.set(record.id, record);
windowsRoot.appendChild(node);
windowsRoot?.appendChild(node);
wireDragging(record);
focusWindow(record.id);
syncTaskbar();
};
const openApp = (app) => {
const existing = Array.from(windows.values()).find((record) => record.definition.app_id === app.app_id);
if (existing) {
existing.node.classList.remove('is-minimized');
focusWindow(existing.id);
return;
}
@@ -190,6 +279,10 @@ if (payloadNode) {
};
const renderWidgets = () => {
if (!widgetZoneRoot) {
return;
}
widgetZoneRoot.innerHTML = '';
payload.widgets.registry
@@ -212,6 +305,10 @@ if (payloadNode) {
};
const renderMenuWidgets = () => {
if (!startMenuWidgets) {
return;
}
startMenuWidgets.innerHTML = '';
payload.widgets.registry.forEach((widget) => {
@@ -274,6 +371,10 @@ if (payloadNode) {
};
const renderStartMenu = () => {
if (!startMenuApps || !startMenuActions) {
return;
}
startMenuApps.innerHTML = '';
startMenuActions.innerHTML = '';
@@ -324,18 +425,18 @@ if (payloadNode) {
<span class="desktop-icon-label">${app.title}</span>
`;
icon.addEventListener('click', () => openApp(app));
iconsRoot.appendChild(icon);
iconsRoot?.appendChild(icon);
});
startButton?.setAttribute('aria-expanded', 'false');
startButton?.addEventListener('click', () => {
if (!startMenu) {
if (!startMenu || !startButton) {
return;
}
const isOpen = !startMenu.hidden;
startMenu.hidden = isOpen;
startButton.setAttribute('aria-expanded', String(!isOpen));
const willOpen = startMenu.hidden;
startMenu.hidden = !willOpen;
startButton.setAttribute('aria-expanded', String(willOpen));
});
document.addEventListener('click', (event) => {