UI Skins
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--shell-text: #f8fafc;
|
||||
--shell-panel: rgba(15, 23, 42, 0.42);
|
||||
--shell-border: rgba(255, 255, 255, 0.16);
|
||||
--card-bg: rgba(255, 255, 255, 0.14);
|
||||
--window-bg: #f8fafc;
|
||||
@@ -10,7 +9,18 @@
|
||||
--accent: #60a5fa;
|
||||
--taskbar-bg: rgba(15, 23, 42, 0.8);
|
||||
--shadow: 0 16px 40px rgba(15, 23, 42, 0.35);
|
||||
font-family: "IBM Plex Sans", "Segoe UI", sans-serif;
|
||||
--desktop-font: "IBM Plex Sans", "Segoe UI", sans-serif;
|
||||
--taskbar-height: 60px;
|
||||
--taskbar-left: 24px;
|
||||
--taskbar-right: 24px;
|
||||
--taskbar-bottom: 24px;
|
||||
--taskbar-width: auto;
|
||||
--taskbar-radius: 22px;
|
||||
--taskbar-justify: flex-start;
|
||||
--stage-top-offset: 0px;
|
||||
--icon-top: 24px;
|
||||
--icon-left: 24px;
|
||||
font-family: var(--desktop-font);
|
||||
}
|
||||
|
||||
* {
|
||||
@@ -24,24 +34,44 @@ body {
|
||||
color: var(--shell-text);
|
||||
}
|
||||
|
||||
body[data-skin="apple"] {
|
||||
--accent: #fb7185;
|
||||
--taskbar-bg: rgba(45, 45, 45, 0.65);
|
||||
--window-bg: #fffbeb;
|
||||
--window-header-bg: #fff1d6;
|
||||
}
|
||||
|
||||
body[data-skin="linux"] {
|
||||
--accent: #f97316;
|
||||
--taskbar-bg: rgba(17, 24, 39, 0.86);
|
||||
--window-bg: #f9fafb;
|
||||
--window-header-bg: #eceff3;
|
||||
}
|
||||
|
||||
.desktop-shell {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.system-bar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 140;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 32px;
|
||||
padding: 0 14px;
|
||||
background: rgba(244, 244, 245, 0.82);
|
||||
color: #111827;
|
||||
backdrop-filter: blur(20px);
|
||||
}
|
||||
|
||||
.system-bar-left,
|
||||
.system-bar-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.system-brand {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.system-divider {
|
||||
width: 1px;
|
||||
height: 14px;
|
||||
background: rgba(17, 24, 39, 0.2);
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
margin: 0 0 12px;
|
||||
text-transform: uppercase;
|
||||
@@ -79,8 +109,8 @@ h1 {
|
||||
|
||||
.desktop-icons {
|
||||
position: absolute;
|
||||
top: 24px;
|
||||
left: 24px;
|
||||
top: var(--icon-top);
|
||||
left: var(--icon-left);
|
||||
z-index: 10;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
|
||||
@@ -123,7 +153,7 @@ h1 {
|
||||
|
||||
.widget-zone {
|
||||
position: absolute;
|
||||
top: 24px;
|
||||
top: calc(var(--stage-top-offset) + 24px);
|
||||
right: 24px;
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
@@ -298,14 +328,17 @@ h1 {
|
||||
|
||||
.taskbar {
|
||||
position: fixed;
|
||||
left: 24px;
|
||||
right: 24px;
|
||||
bottom: 24px;
|
||||
left: var(--taskbar-left);
|
||||
right: var(--taskbar-right);
|
||||
bottom: var(--taskbar-bottom);
|
||||
width: var(--taskbar-width);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
justify-content: var(--taskbar-justify);
|
||||
min-height: var(--taskbar-height);
|
||||
padding: 12px 16px;
|
||||
border-radius: 22px;
|
||||
border-radius: var(--taskbar-radius);
|
||||
background: var(--taskbar-bg);
|
||||
backdrop-filter: blur(18px);
|
||||
border: 1px solid var(--shell-border);
|
||||
@@ -322,6 +355,18 @@ h1 {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.start-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.start-button-icon {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.taskbar-app-button.is-focused {
|
||||
background: var(--accent);
|
||||
color: #0f172a;
|
||||
@@ -334,7 +379,7 @@ h1 {
|
||||
.start-menu {
|
||||
position: fixed;
|
||||
left: 24px;
|
||||
bottom: 102px;
|
||||
bottom: calc(var(--taskbar-height) + 28px);
|
||||
z-index: 130;
|
||||
display: grid;
|
||||
align-content: start;
|
||||
@@ -485,6 +530,7 @@ h1 {
|
||||
left: 16px;
|
||||
right: 16px;
|
||||
bottom: 88px;
|
||||
transform: none;
|
||||
width: auto;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
@@ -12,10 +12,14 @@ if (payloadNode) {
|
||||
const startMenuWidgets = document.getElementById('start-menu-widgets');
|
||||
const startMenuActions = document.getElementById('start-menu-actions');
|
||||
const traySkins = document.getElementById('tray-skins');
|
||||
const traySkinsTop = document.getElementById('tray-skins-top');
|
||||
const clockNode = document.getElementById('clock');
|
||||
const clockTopNode = document.getElementById('clock-top');
|
||||
const windows = new Map();
|
||||
const activeWidgets = new Set(payload.widgets.active_ids);
|
||||
const activeSkin = payload.meta.active_skin;
|
||||
const skinProfile = payload.meta.skin_profile || {};
|
||||
const maximizeOverSystemBar = Boolean(skinProfile.maximize_over_system_bar);
|
||||
const storageScope = payload.desktop.storage_scope || 'guest';
|
||||
const storageKey = `desktop.kusche.berlin.window-state.${storageScope}`;
|
||||
let zIndex = 20;
|
||||
@@ -57,10 +61,12 @@ if (payloadNode) {
|
||||
}
|
||||
|
||||
const taskbar = document.querySelector('.taskbar');
|
||||
const systemBar = document.querySelector('.system-bar');
|
||||
const stageRect = windowsRoot.getBoundingClientRect();
|
||||
const taskbarRect = taskbar ? taskbar.getBoundingClientRect() : null;
|
||||
const systemBarRect = systemBar ? systemBar.getBoundingClientRect() : null;
|
||||
|
||||
topDesktopInset = 0;
|
||||
topDesktopInset = systemBarRect ? Math.round(systemBarRect.height) : 0;
|
||||
sideDesktopInset = 0;
|
||||
bottomDesktopInset = taskbarRect
|
||||
? Math.max(0, Math.round(stageRect.bottom - taskbarRect.top))
|
||||
@@ -82,15 +88,19 @@ if (payloadNode) {
|
||||
};
|
||||
|
||||
const renderClock = () => {
|
||||
if (!clockNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
clockNode.textContent = new Intl.DateTimeFormat('de-DE', {
|
||||
const formatted = new Intl.DateTimeFormat('de-DE', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
}).format(new Date());
|
||||
|
||||
if (clockNode) {
|
||||
clockNode.textContent = formatted;
|
||||
}
|
||||
|
||||
if (clockTopNode) {
|
||||
clockTopNode.textContent = formatted;
|
||||
}
|
||||
};
|
||||
|
||||
const navigateToSkin = (skin) => {
|
||||
@@ -98,20 +108,22 @@ if (payloadNode) {
|
||||
};
|
||||
|
||||
const renderTraySkins = () => {
|
||||
if (!traySkins) {
|
||||
return;
|
||||
}
|
||||
[traySkins, traySkinsTop].forEach((container) => {
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
traySkins.innerHTML = '';
|
||||
container.innerHTML = '';
|
||||
|
||||
payload.meta.available_skins.forEach((skin) => {
|
||||
const button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.className = `tray-skin-button${skin === activeSkin ? ' is-active' : ''}`;
|
||||
button.textContent = skin.slice(0, 3).toUpperCase();
|
||||
button.title = skin;
|
||||
button.addEventListener('click', () => navigateToSkin(skin));
|
||||
traySkins.appendChild(button);
|
||||
payload.meta.available_skins.forEach((skin) => {
|
||||
const button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.className = `tray-skin-button${skin === activeSkin ? ' is-active' : ''}`;
|
||||
button.textContent = skin.slice(0, 3).toUpperCase();
|
||||
button.title = skin;
|
||||
button.addEventListener('click', () => navigateToSkin(skin));
|
||||
container.appendChild(button);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -184,12 +196,13 @@ if (payloadNode) {
|
||||
record.state.maximized = true;
|
||||
record.node.classList.add('is-maximized');
|
||||
measureDesktopBounds();
|
||||
const maximizedTopInset = maximizeOverSystemBar ? 0 : topDesktopInset;
|
||||
record.node.style.left = `${sideDesktopInset}px`;
|
||||
record.node.style.top = `${topDesktopInset}px`;
|
||||
record.node.style.top = `${maximizedTopInset}px`;
|
||||
record.node.style.width = sideDesktopInset === 0 ? '100%' : `calc(100% - ${sideDesktopInset * 2}px)`;
|
||||
record.node.style.height = activeSkin === 'apple'
|
||||
record.node.style.height = maximizeOverSystemBar
|
||||
? '100%'
|
||||
: `calc(100% - ${topDesktopInset + bottomDesktopInset}px)`;
|
||||
: `calc(100% - ${maximizedTopInset + bottomDesktopInset}px)`;
|
||||
focusWindow(windowId);
|
||||
saveWindowState();
|
||||
return;
|
||||
@@ -417,12 +430,13 @@ if (payloadNode) {
|
||||
if (record.state.maximized) {
|
||||
record.node.classList.add('is-maximized');
|
||||
measureDesktopBounds();
|
||||
const maximizedTopInset = maximizeOverSystemBar ? 0 : topDesktopInset;
|
||||
record.node.style.left = `${sideDesktopInset}px`;
|
||||
record.node.style.top = `${topDesktopInset}px`;
|
||||
record.node.style.top = `${maximizedTopInset}px`;
|
||||
record.node.style.width = sideDesktopInset === 0 ? '100%' : `calc(100% - ${sideDesktopInset * 2}px)`;
|
||||
record.node.style.height = activeSkin === 'apple'
|
||||
record.node.style.height = maximizeOverSystemBar
|
||||
? '100%'
|
||||
: `calc(100% - ${topDesktopInset + bottomDesktopInset}px)`;
|
||||
: `calc(100% - ${maximizedTopInset + bottomDesktopInset}px)`;
|
||||
}
|
||||
|
||||
node.addEventListener('mousedown', () => focusWindow(record.id));
|
||||
|
||||
16
public/assets/desktop/skins/apple/profile.php
Normal file
16
public/assets/desktop/skins/apple/profile.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'id' => 'apple',
|
||||
'label' => 'Apple',
|
||||
'family' => 'apple',
|
||||
'wallpaper' => 'radial-gradient(circle at top, #ffe7ba 0%, #ff9a62 38%, #531b53 100%)',
|
||||
'top_bar' => true,
|
||||
'taskbar_mode' => 'dock',
|
||||
'taskbar_label' => 'Launchpad',
|
||||
'taskbar_icon' => 'Mac',
|
||||
'window_controls' => 'mac',
|
||||
'maximize_over_system_bar' => true,
|
||||
];
|
||||
50
public/assets/desktop/skins/apple/skin.css
Normal file
50
public/assets/desktop/skins/apple/skin.css
Normal file
@@ -0,0 +1,50 @@
|
||||
body[data-skin="apple"] {
|
||||
--accent: #fb7185;
|
||||
--taskbar-bg: rgba(45, 45, 45, 0.65);
|
||||
--window-bg: #fffbeb;
|
||||
--window-header-bg: #fff1d6;
|
||||
--desktop-font: "SF Pro Display", "Helvetica Neue", sans-serif;
|
||||
--taskbar-height: 72px;
|
||||
--taskbar-left: 50%;
|
||||
--taskbar-right: auto;
|
||||
--taskbar-bottom: 18px;
|
||||
--taskbar-width: auto;
|
||||
--taskbar-radius: 24px;
|
||||
--taskbar-justify: center;
|
||||
--stage-top-offset: 34px;
|
||||
--icon-top: 56px;
|
||||
}
|
||||
|
||||
body[data-skin="apple"] .system-bar {
|
||||
background: rgba(244, 244, 245, 0.82);
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
body[data-skin="apple"] .taskbar {
|
||||
transform: translateX(-50%);
|
||||
border: 1px solid rgba(255, 255, 255, 0.26);
|
||||
box-shadow: 0 18px 40px rgba(17, 24, 39, 0.22);
|
||||
}
|
||||
|
||||
body[data-skin="apple"] .start-button {
|
||||
order: 2;
|
||||
min-width: 92px;
|
||||
justify-content: center;
|
||||
background: rgba(255, 255, 255, 0.24);
|
||||
}
|
||||
|
||||
body[data-skin="apple"] .tray {
|
||||
order: 1;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
body[data-skin="apple"] .taskbar-apps {
|
||||
order: 3;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
body[data-skin="apple"] .start-menu {
|
||||
left: 50%;
|
||||
bottom: 106px;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
16
public/assets/desktop/skins/base/profile.php
Normal file
16
public/assets/desktop/skins/base/profile.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'id' => 'base',
|
||||
'label' => 'Base',
|
||||
'family' => 'base',
|
||||
'wallpaper' => 'linear-gradient(160deg, #1d4ed8 0%, #0f172a 100%)',
|
||||
'top_bar' => false,
|
||||
'taskbar_mode' => 'taskbar',
|
||||
'taskbar_label' => 'Menu',
|
||||
'taskbar_icon' => 'OS',
|
||||
'window_controls' => 'windows',
|
||||
'maximize_over_system_bar' => false,
|
||||
];
|
||||
24
public/assets/desktop/skins/base/skin.css
Normal file
24
public/assets/desktop/skins/base/skin.css
Normal file
@@ -0,0 +1,24 @@
|
||||
.tray-skins,
|
||||
.system-skins {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.tray-skin-button {
|
||||
min-width: 38px;
|
||||
height: 28px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
color: inherit;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tray-skin-button.is-active {
|
||||
background: rgba(255, 255, 255, 0.24);
|
||||
}
|
||||
16
public/assets/desktop/skins/linux/profile.php
Normal file
16
public/assets/desktop/skins/linux/profile.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'id' => 'linux',
|
||||
'label' => 'Linux Mint',
|
||||
'family' => 'linux-mint',
|
||||
'wallpaper' => 'linear-gradient(140deg, #123329 0%, #1f5d4f 45%, #0f172a 100%)',
|
||||
'top_bar' => false,
|
||||
'taskbar_mode' => 'panel',
|
||||
'taskbar_label' => 'Menu',
|
||||
'taskbar_icon' => 'Mint',
|
||||
'window_controls' => 'linux',
|
||||
'maximize_over_system_bar' => false,
|
||||
];
|
||||
33
public/assets/desktop/skins/linux/skin.css
Normal file
33
public/assets/desktop/skins/linux/skin.css
Normal file
@@ -0,0 +1,33 @@
|
||||
body[data-skin="linux"] {
|
||||
--accent: #86efac;
|
||||
--taskbar-bg: linear-gradient(180deg, rgba(33, 46, 42, 0.98), rgba(21, 31, 28, 0.98));
|
||||
--window-bg: #f9fafb;
|
||||
--window-header-bg: #eceff3;
|
||||
--desktop-font: "Noto Sans", "Ubuntu", sans-serif;
|
||||
--taskbar-height: 48px;
|
||||
--taskbar-left: 0;
|
||||
--taskbar-right: 0;
|
||||
--taskbar-bottom: 0;
|
||||
--taskbar-width: 100%;
|
||||
--taskbar-radius: 0;
|
||||
--taskbar-justify: flex-start;
|
||||
}
|
||||
|
||||
body[data-skin="linux"] .taskbar {
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
backdrop-filter: none;
|
||||
box-shadow: 0 -10px 24px rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
|
||||
body[data-skin="linux"] .start-button {
|
||||
border-radius: 10px;
|
||||
background: linear-gradient(180deg, rgba(92, 185, 118, 0.24), rgba(55, 110, 75, 0.28));
|
||||
}
|
||||
|
||||
body[data-skin="linux"] .start-menu {
|
||||
left: 12px;
|
||||
bottom: 58px;
|
||||
border-radius: 18px 18px 0 0;
|
||||
}
|
||||
16
public/assets/desktop/skins/windows/profile.php
Normal file
16
public/assets/desktop/skins/windows/profile.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'id' => 'windows',
|
||||
'label' => 'Windows',
|
||||
'family' => 'windows',
|
||||
'wallpaper' => 'linear-gradient(160deg, #1d4ed8 0%, #0f172a 100%)',
|
||||
'top_bar' => false,
|
||||
'taskbar_mode' => 'taskbar',
|
||||
'taskbar_label' => 'Start',
|
||||
'taskbar_icon' => 'Win',
|
||||
'window_controls' => 'windows',
|
||||
'maximize_over_system_bar' => false,
|
||||
];
|
||||
37
public/assets/desktop/skins/windows/skin.css
Normal file
37
public/assets/desktop/skins/windows/skin.css
Normal file
@@ -0,0 +1,37 @@
|
||||
body[data-skin="windows"] {
|
||||
--accent: #60a5fa;
|
||||
--taskbar-bg: linear-gradient(180deg, rgba(24, 39, 75, 0.94), rgba(15, 23, 42, 0.96));
|
||||
--window-bg: #f8fafc;
|
||||
--window-header-bg: linear-gradient(180deg, #eff6ff, #dbeafe);
|
||||
--desktop-font: "Segoe UI", "IBM Plex Sans", sans-serif;
|
||||
--taskbar-height: 54px;
|
||||
--taskbar-left: 0;
|
||||
--taskbar-right: 0;
|
||||
--taskbar-bottom: 0;
|
||||
--taskbar-width: 100%;
|
||||
--taskbar-radius: 0;
|
||||
--taskbar-justify: flex-start;
|
||||
--icon-top: 22px;
|
||||
--icon-left: 24px;
|
||||
}
|
||||
|
||||
body[data-skin="windows"] .taskbar {
|
||||
padding: 8px 14px;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
body[data-skin="windows"] .start-button {
|
||||
min-width: 94px;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.14);
|
||||
}
|
||||
|
||||
body[data-skin="windows"] .start-menu {
|
||||
left: 12px;
|
||||
bottom: 62px;
|
||||
border-radius: 14px 14px 0 0;
|
||||
}
|
||||
Reference in New Issue
Block a user