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