ddsfsf
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user