UI Skins
All checks were successful
Deploy / deploy-staging (push) Successful in 11s
Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-06-08 00:30:18 +02:00
parent 538175e52e
commit a8b197592b
14 changed files with 476 additions and 57 deletions

View File

@@ -34,6 +34,8 @@ final class App
'title' => 'Kusche.Berlin Desktop UI',
'active_skin' => $activeSkin,
'available_skins' => $skins,
'base_skin_profile' => SkinResolver::profile('base'),
'skin_profile' => SkinResolver::profile($activeSkin),
],
'desktop' => [
'greeting' => 'Neue Desktop-Shell fuer Kusche.Berlin',

View File

@@ -6,27 +6,131 @@ namespace Desktop;
final class SkinResolver
{
private const DEFAULT_SKIN = 'windows';
/**
* @return array<int, string>
*/
public static function all(): array
{
return ['windows', 'apple', 'linux'];
return array_values(array_filter(
array_keys(self::profiles()),
static fn (string $skin): bool => $skin !== 'base'
));
}
public static function resolve(?string $requestedSkin): string
{
$skin = strtolower((string) $requestedSkin);
return in_array($skin, self::all(), true) ? $skin : 'windows';
return in_array($skin, self::all(), true) ? $skin : self::DEFAULT_SKIN;
}
public static function wallpaper(string $skin): string
{
return match ($skin) {
'apple' => 'radial-gradient(circle at top, #ffe7ba 0%, #ff9a62 38%, #531b53 100%)',
'linux' => 'linear-gradient(140deg, #111827 0%, #1f2937 40%, #ea580c 100%)',
default => 'linear-gradient(160deg, #1d4ed8 0%, #0f172a 100%)',
};
return (string) (self::profile($skin)['wallpaper'] ?? '');
}
/**
* @return array<string, array<string, mixed>>
*/
public static function profiles(): array
{
static $profiles;
if (is_array($profiles)) {
return $profiles;
}
$profiles = [];
$skinsPath = self::skinsPath();
$directories = glob($skinsPath . '/*', GLOB_ONLYDIR) ?: [];
foreach ($directories as $directory) {
$skinId = basename($directory);
$profilePath = $directory . '/profile.php';
if (!is_file($profilePath)) {
continue;
}
/** @var array<string, mixed> $profile */
$profile = require $profilePath;
$profiles[$skinId] = array_merge(
[
'id' => $skinId,
'label' => ucfirst($skinId),
'family' => $skinId,
'wallpaper' => '',
'top_bar' => false,
'taskbar_mode' => 'taskbar',
'taskbar_label' => 'Menu',
'taskbar_icon' => strtoupper(substr($skinId, 0, 3)),
'window_controls' => 'windows',
'maximize_over_system_bar' => false,
],
$profile,
self::assetManifest($skinId)
);
}
if (!isset($profiles['base'])) {
$profiles['base'] = array_merge(
[
'id' => 'base',
'label' => 'Base',
'family' => 'base',
'wallpaper' => '',
'top_bar' => false,
'taskbar_mode' => 'taskbar',
'taskbar_label' => 'Menu',
'taskbar_icon' => 'OS',
'window_controls' => 'windows',
'maximize_over_system_bar' => false,
],
self::assetManifest('base')
);
}
return $profiles;
}
/**
* @return array<string, mixed>
*/
public static function profile(string $skin): array
{
$profiles = self::profiles();
$baseProfile = $profiles['base'] ?? [];
if ($skin === 'base') {
return $baseProfile;
}
$resolvedSkin = self::resolve($skin);
return array_merge(
$baseProfile,
$profiles[$resolvedSkin] ?? $profiles[self::DEFAULT_SKIN] ?? $baseProfile
);
}
private static function skinsPath(): string
{
return dirname(__DIR__, 2) . '/public/assets/desktop/skins';
}
/**
* @return array<string, string|null>
*/
private static function assetManifest(string $skin): array
{
$basePath = self::skinsPath() . '/' . $skin;
$publicBasePath = '/assets/desktop/skins/' . $skin;
return [
'css_path' => is_file($basePath . '/skin.css') ? $publicBasePath . '/skin.css' : null,
'js_path' => is_file($basePath . '/skin.js') ? $publicBasePath . '/skin.js' : null,
];
}
}