Ui
This commit is contained in:
@@ -7,6 +7,17 @@ $activeSkin = $desktopPayload['meta']['active_skin'];
|
||||
$baseSkinProfile = $desktopPayload['meta']['base_skin_profile'];
|
||||
$skinProfile = $desktopPayload['meta']['skin_profile'];
|
||||
$wallpaper = $desktopPayload['desktop']['wallpaper'];
|
||||
|
||||
$renderStartIcon = static function (array $profile): string {
|
||||
$style = (string) ($profile['taskbar_icon_style'] ?? 'label');
|
||||
|
||||
return match ($style) {
|
||||
'windows' => '<span class="start-glyph start-glyph-windows" aria-hidden="true"><span></span><span></span><span></span><span></span></span>',
|
||||
'apple' => '<span class="start-glyph start-glyph-apple" aria-hidden="true"></span>',
|
||||
'linux' => '<span class="start-glyph start-glyph-linux" aria-hidden="true"><span></span><span></span><span></span></span>',
|
||||
default => '<span class="start-glyph start-glyph-label" aria-hidden="true">' . htmlspecialchars((string) ($profile['taskbar_icon'] ?? 'OS'), ENT_QUOTES) . '</span>',
|
||||
};
|
||||
};
|
||||
?><!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
@@ -25,6 +36,7 @@ $wallpaper = $desktopPayload['desktop']['wallpaper'];
|
||||
data-skin="<?= htmlspecialchars($activeSkin, ENT_QUOTES) ?>"
|
||||
data-skin-family="<?= htmlspecialchars((string) ($skinProfile['family'] ?? $activeSkin), ENT_QUOTES) ?>"
|
||||
data-taskbar-mode="<?= htmlspecialchars((string) ($skinProfile['taskbar_mode'] ?? 'taskbar'), ENT_QUOTES) ?>"
|
||||
data-window-controls="<?= htmlspecialchars((string) ($skinProfile['window_controls'] ?? 'windows'), ENT_QUOTES) ?>"
|
||||
style="--wallpaper: <?= htmlspecialchars($wallpaper, ENT_QUOTES) ?>;"
|
||||
>
|
||||
<div class="desktop-shell">
|
||||
@@ -92,7 +104,7 @@ $wallpaper = $desktopPayload['desktop']['wallpaper'];
|
||||
|
||||
<footer class="taskbar">
|
||||
<button class="start-button" id="start-button" type="button">
|
||||
<span class="start-button-icon"><?= htmlspecialchars((string) ($skinProfile['taskbar_icon'] ?? ''), ENT_QUOTES) ?></span>
|
||||
<span class="start-button-icon"><?= $renderStartIcon($skinProfile) ?></span>
|
||||
<span class="start-button-label"><?= htmlspecialchars((string) ($skinProfile['taskbar_label'] ?? 'Menu'), ENT_QUOTES) ?></span>
|
||||
</button>
|
||||
<div class="taskbar-apps" id="taskbar-apps"></div>
|
||||
|
||||
@@ -293,12 +293,29 @@ h1 {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.window-title {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
.window-header-spacer {
|
||||
width: 64px;
|
||||
flex: 0 0 64px;
|
||||
}
|
||||
|
||||
.window-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.window-action {
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
padding: 0;
|
||||
@@ -308,6 +325,11 @@ h1 {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.window-action span {
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.window-action[data-action="close"] {
|
||||
background: #ef4444;
|
||||
}
|
||||
@@ -362,9 +384,12 @@ h1 {
|
||||
}
|
||||
|
||||
.start-button-icon {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
opacity: 0.8;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
flex: 0 0 18px;
|
||||
}
|
||||
|
||||
.taskbar-app-button.is-focused {
|
||||
@@ -376,6 +401,71 @@ h1 {
|
||||
opacity: 0.62;
|
||||
}
|
||||
|
||||
.start-glyph {
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.start-glyph-windows {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 2px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.start-glyph-windows span {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
background: currentColor;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.start-glyph-apple {
|
||||
position: relative;
|
||||
width: 14px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.start-glyph-apple::before,
|
||||
.start-glyph-apple::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
background: currentColor;
|
||||
}
|
||||
|
||||
.start-glyph-apple::before {
|
||||
inset: 3px 1px 0;
|
||||
border-radius: 48% 48% 42% 42% / 42% 42% 58% 58%;
|
||||
}
|
||||
|
||||
.start-glyph-apple::after {
|
||||
top: 0;
|
||||
right: 3px;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-radius: 0 100% 0 100%;
|
||||
transform: rotate(-24deg);
|
||||
}
|
||||
|
||||
.start-glyph-linux {
|
||||
gap: 2px;
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
.start-glyph-linux span {
|
||||
display: block;
|
||||
width: 14px;
|
||||
height: 3px;
|
||||
border-radius: 999px;
|
||||
background: currentColor;
|
||||
}
|
||||
|
||||
.start-glyph-label {
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.start-menu {
|
||||
position: fixed;
|
||||
left: 24px;
|
||||
@@ -470,6 +560,29 @@ h1 {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.taskbar-app-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.taskbar-app-button-badge {
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: 8px;
|
||||
background: rgba(15, 23, 42, 0.22);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.taskbar-app-button-label {
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tray {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -26,6 +26,62 @@ if (payloadNode) {
|
||||
let topDesktopInset = 0;
|
||||
let sideDesktopInset = 0;
|
||||
let bottomDesktopInset = 120;
|
||||
const windowControlsMode = document.body.dataset.windowControls || 'windows';
|
||||
|
||||
const escapeHtml = (value) => String(value)
|
||||
.replaceAll('&', '&')
|
||||
.replaceAll('<', '<')
|
||||
.replaceAll('>', '>')
|
||||
.replaceAll('"', '"')
|
||||
.replaceAll("'", ''');
|
||||
|
||||
const buildTaskbarButtonContent = (record) => `
|
||||
<span class="taskbar-app-button-badge">${escapeHtml(record.definition.icon || 'AP')}</span>
|
||||
<span class="taskbar-app-button-label">${escapeHtml(record.title)}</span>
|
||||
`;
|
||||
|
||||
const buildWindowActions = () => {
|
||||
if (windowControlsMode === 'mac') {
|
||||
return `
|
||||
<div class="window-actions window-actions--mac">
|
||||
<button class="window-action" data-action="close" type="button" aria-label="Schliessen"></button>
|
||||
<button class="window-action" data-action="minimize" type="button" aria-label="Minimieren"></button>
|
||||
<button class="window-action" data-action="maximize" type="button" aria-label="Maximieren"></button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
const maximizeGlyph = windowControlsMode === 'linux' ? '▢' : '□';
|
||||
|
||||
return `
|
||||
<div class="window-actions window-actions--${windowControlsMode}">
|
||||
<button class="window-action" data-action="minimize" type="button" aria-label="Minimieren"><span>-</span></button>
|
||||
<button class="window-action" data-action="maximize" type="button" aria-label="Maximieren"><span>${maximizeGlyph}</span></button>
|
||||
<button class="window-action" data-action="close" type="button" aria-label="Schliessen"><span>×</span></button>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
|
||||
const buildWindowHeader = (definition) => {
|
||||
const title = escapeHtml(definition.title);
|
||||
|
||||
if (windowControlsMode === 'mac') {
|
||||
return `
|
||||
<header class="window-header window-header--mac">
|
||||
${buildWindowActions()}
|
||||
<strong class="window-title">${title}</strong>
|
||||
<span class="window-header-spacer" aria-hidden="true"></span>
|
||||
</header>
|
||||
`;
|
||||
}
|
||||
|
||||
return `
|
||||
<header class="window-header window-header--${windowControlsMode}">
|
||||
<strong class="window-title">${title}</strong>
|
||||
${buildWindowActions()}
|
||||
</header>
|
||||
`;
|
||||
};
|
||||
|
||||
const loadWindowState = () => {
|
||||
try {
|
||||
@@ -247,7 +303,7 @@ if (payloadNode) {
|
||||
} else if (record.node.classList.contains('is-focused')) {
|
||||
button.classList.add('is-focused');
|
||||
}
|
||||
button.textContent = record.title;
|
||||
button.innerHTML = buildTaskbarButtonContent(record);
|
||||
button.addEventListener('click', () => {
|
||||
if (record.state.minimized) {
|
||||
toggleMinimize(record.id);
|
||||
@@ -380,18 +436,12 @@ if (payloadNode) {
|
||||
const createWindow = (definition) => {
|
||||
const node = document.createElement('article');
|
||||
node.className = 'window';
|
||||
node.dataset.windowControls = windowControlsMode;
|
||||
node.innerHTML = `
|
||||
<header class="window-header">
|
||||
<strong>${definition.title}</strong>
|
||||
<div class="window-actions">
|
||||
<button class="window-action" data-action="minimize" type="button" aria-label="Minimieren"></button>
|
||||
<button class="window-action" data-action="maximize" type="button" aria-label="Maximieren"></button>
|
||||
<button class="window-action" data-action="close" type="button" aria-label="Schliessen"></button>
|
||||
</div>
|
||||
</header>
|
||||
${buildWindowHeader(definition)}
|
||||
<div class="window-content">
|
||||
<p>${definition.content}</p>
|
||||
<p><strong>Route:</strong> ${definition.app_id}</p>
|
||||
<p>${escapeHtml(definition.content)}</p>
|
||||
<p><strong>Route:</strong> ${escapeHtml(definition.app_id)}</p>
|
||||
</div>
|
||||
<div class="window-resize-handle" data-edge="top" aria-hidden="true"></div>
|
||||
<div class="window-resize-handle" data-edge="right" aria-hidden="true"></div>
|
||||
|
||||
@@ -11,6 +11,7 @@ return [
|
||||
'taskbar_mode' => 'dock',
|
||||
'taskbar_label' => 'Launchpad',
|
||||
'taskbar_icon' => 'Mac',
|
||||
'taskbar_icon_style' => 'apple',
|
||||
'window_controls' => 'mac',
|
||||
'maximize_over_system_bar' => true,
|
||||
];
|
||||
|
||||
@@ -48,3 +48,51 @@ body[data-skin="apple"] .start-menu {
|
||||
bottom: 106px;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
body[data-skin="apple"] .window {
|
||||
border-radius: 14px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.58);
|
||||
box-shadow: 0 28px 70px rgba(17, 24, 39, 0.24);
|
||||
}
|
||||
|
||||
body[data-skin="apple"] .window-header {
|
||||
position: relative;
|
||||
min-height: 42px;
|
||||
justify-content: flex-start;
|
||||
gap: 14px;
|
||||
padding: 10px 14px;
|
||||
background: linear-gradient(180deg, #fff7eb, #fde9c9);
|
||||
}
|
||||
|
||||
body[data-skin="apple"] .window-title {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
font-size: 13px;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
body[data-skin="apple"] .window-action {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
body[data-skin="apple"] .window-action span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body[data-skin="apple"] .taskbar-app-button {
|
||||
min-width: 56px;
|
||||
padding: 10px 12px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
body[data-skin="apple"] .taskbar-app-button-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body[data-skin="apple"] .taskbar-app-button-badge {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ return [
|
||||
'taskbar_mode' => 'taskbar',
|
||||
'taskbar_label' => 'Menu',
|
||||
'taskbar_icon' => 'OS',
|
||||
'taskbar_icon_style' => 'label',
|
||||
'window_controls' => 'windows',
|
||||
'maximize_over_system_bar' => false,
|
||||
];
|
||||
|
||||
@@ -11,6 +11,7 @@ return [
|
||||
'taskbar_mode' => 'panel',
|
||||
'taskbar_label' => 'Menu',
|
||||
'taskbar_icon' => 'Mint',
|
||||
'taskbar_icon_style' => 'linux',
|
||||
'window_controls' => 'linux',
|
||||
'maximize_over_system_bar' => false,
|
||||
];
|
||||
|
||||
@@ -31,3 +31,46 @@ body[data-skin="linux"] .start-menu {
|
||||
bottom: 58px;
|
||||
border-radius: 18px 18px 0 0;
|
||||
}
|
||||
|
||||
body[data-skin="linux"] .window {
|
||||
border-radius: 8px 8px 0 0;
|
||||
border: 1px solid rgba(71, 85, 105, 0.42);
|
||||
}
|
||||
|
||||
body[data-skin="linux"] .window-header {
|
||||
min-height: 34px;
|
||||
padding: 7px 8px 7px 12px;
|
||||
background: linear-gradient(180deg, #eef1f4, #dce2e8);
|
||||
}
|
||||
|
||||
body[data-skin="linux"] .window-title {
|
||||
font-size: 13px;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
body[data-skin="linux"] .window-actions {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
body[data-skin="linux"] .window-action {
|
||||
width: 26px;
|
||||
height: 22px;
|
||||
border-radius: 4px;
|
||||
background: linear-gradient(180deg, #f9fafb, #dbe4ea);
|
||||
border: 1px solid rgba(100, 116, 139, 0.45);
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
body[data-skin="linux"] .window-action[data-action="close"] {
|
||||
background: linear-gradient(180deg, #fca5a5, #ef4444);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body[data-skin="linux"] .window-action span {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
body[data-skin="linux"] .taskbar-app-button {
|
||||
border-radius: 6px;
|
||||
min-width: 136px;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ return [
|
||||
'taskbar_mode' => 'taskbar',
|
||||
'taskbar_label' => 'Start',
|
||||
'taskbar_icon' => 'Win',
|
||||
'taskbar_icon_style' => 'windows',
|
||||
'window_controls' => 'windows',
|
||||
'maximize_over_system_bar' => false,
|
||||
];
|
||||
|
||||
@@ -26,8 +26,8 @@ body[data-skin="windows"] .taskbar {
|
||||
body[data-skin="windows"] .start-button {
|
||||
min-width: 94px;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.14);
|
||||
border-radius: 6px;
|
||||
background: linear-gradient(180deg, rgba(76, 144, 255, 0.4), rgba(35, 86, 171, 0.4));
|
||||
}
|
||||
|
||||
body[data-skin="windows"] .start-menu {
|
||||
@@ -35,3 +35,50 @@ body[data-skin="windows"] .start-menu {
|
||||
bottom: 62px;
|
||||
border-radius: 14px 14px 0 0;
|
||||
}
|
||||
|
||||
body[data-skin="windows"] .window {
|
||||
border-radius: 10px 10px 0 0;
|
||||
border: 1px solid rgba(69, 120, 194, 0.45);
|
||||
}
|
||||
|
||||
body[data-skin="windows"] .window-header {
|
||||
min-height: 38px;
|
||||
padding: 8px 8px 8px 14px;
|
||||
background: linear-gradient(180deg, #eff7ff, #dcecff 54%, #cae0fb);
|
||||
}
|
||||
|
||||
body[data-skin="windows"] .window-title {
|
||||
color: #12345b;
|
||||
}
|
||||
|
||||
body[data-skin="windows"] .window-actions {
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
body[data-skin="windows"] .window-action {
|
||||
width: 42px;
|
||||
height: 28px;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
color: #12345b;
|
||||
}
|
||||
|
||||
body[data-skin="windows"] .window-action:hover {
|
||||
background: rgba(29, 78, 216, 0.12);
|
||||
}
|
||||
|
||||
body[data-skin="windows"] .window-action[data-action="close"]:hover {
|
||||
background: #dc2626;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body[data-skin="windows"] .window-action span {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
body[data-skin="windows"] .taskbar-app-button {
|
||||
border-radius: 6px;
|
||||
min-width: 148px;
|
||||
background: rgba(255, 255, 255, 0.14);
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ final class SkinResolver
|
||||
'taskbar_mode' => 'taskbar',
|
||||
'taskbar_label' => 'Menu',
|
||||
'taskbar_icon' => strtoupper(substr($skinId, 0, 3)),
|
||||
'taskbar_icon_style' => 'label',
|
||||
'window_controls' => 'windows',
|
||||
'maximize_over_system_bar' => false,
|
||||
],
|
||||
@@ -85,6 +86,7 @@ final class SkinResolver
|
||||
'taskbar_mode' => 'taskbar',
|
||||
'taskbar_label' => 'Menu',
|
||||
'taskbar_icon' => 'OS',
|
||||
'taskbar_icon_style' => 'label',
|
||||
'window_controls' => 'windows',
|
||||
'maximize_over_system_bar' => false,
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user