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

View File

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

View File

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