New desktop
Some checks failed
Deploy / deploy-staging (push) Failing after 6s
Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-06-06 03:20:50 +02:00
parent 756b4e119b
commit 888981c782
127 changed files with 31275 additions and 0 deletions

51
src/App/App.php Normal file
View File

@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace App;
use Desktop\AppRegistry;
use Desktop\DesktopState;
use Desktop\SkinResolver;
use Desktop\WindowManager;
final class App
{
public function __construct(
private readonly string $projectRoot,
) {
}
/**
* @return array<string, mixed>
*/
public function desktopPayload(): array
{
$registry = new AppRegistry($this->projectRoot . '/config/apps.php');
$skins = SkinResolver::all();
$activeSkin = SkinResolver::resolve($_GET['skin'] ?? null);
$windows = (new WindowManager($registry))->defaultWindows();
return [
'meta' => [
'title' => 'Kusche.Berlin Desktop UI',
'active_skin' => $activeSkin,
'available_skins' => $skins,
],
'desktop' => [
'greeting' => 'Neue Desktop-Shell fuer Kusche.Berlin',
'wallpaper' => SkinResolver::wallpaper($activeSkin),
'workspace' => DesktopState::defaultWorkspace(),
'login' => [
'authenticated' => false,
'mode' => 'public-home',
'keycloak_theme_handoff' => '/docs/keycloak-theme-handoff.md',
],
],
'apps' => $registry->all(),
'windows' => $windows,
'widgets' => DesktopState::defaultWidgets(),
'tray' => DesktopState::trayItems(),
];
}
}

23
src/App/bootstrap.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
spl_autoload_register(static function (string $class): void {
$prefixes = [
'App\\' => __DIR__ . '/',
'Desktop\\' => dirname(__DIR__) . '/Desktop/',
];
foreach ($prefixes as $prefix => $baseDir) {
if (!str_starts_with($class, $prefix)) {
continue;
}
$relative = substr($class, strlen($prefix));
$path = $baseDir . str_replace('\\', '/', $relative) . '.php';
if (is_file($path)) {
require_once $path;
}
}
});

View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace Desktop;
final class AppRegistry
{
/** @var array<int, array<string, mixed>> */
private array $apps;
public function __construct(string $configPath)
{
/** @var array<int, array<string, mixed>> $apps */
$apps = require $configPath;
$this->apps = $apps;
}
/**
* @return array<int, array<string, mixed>>
*/
public function all(): array
{
return $this->apps;
}
/**
* @return array<string, mixed>|null
*/
public function find(string $appId): ?array
{
foreach ($this->apps as $app) {
if (($app['app_id'] ?? null) === $appId) {
return $app;
}
}
return null;
}
}

View File

@@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace Desktop;
final class DesktopState
{
/**
* @return array<string, mixed>
*/
public static function defaultWorkspace(): array
{
return [
'workspace_id' => 'default',
'title' => 'Persoenlicher Desktop',
'supports_public_home' => true,
'supports_multi_workspace' => true,
];
}
/**
* @return array<int, array<string, string>>
*/
public static function defaultWidgets(): array
{
return [
[
'widget_id' => 'public-home',
'title' => 'Public Home',
'content' => 'Oeffentliches Dashboard als Startzustand fuer nicht eingeloggte Nutzer.',
],
[
'widget_id' => 'personal-links',
'title' => 'Persoenliche Links',
'content' => 'Platzhalter fuer spaetere user-spezifische Linklisten und Dashboards.',
],
];
}
/**
* @return array<int, array<string, string>>
*/
public static function trayItems(): array
{
return [
['id' => 'network', 'label' => 'Netzwerk'],
['id' => 'widgets', 'label' => 'Widgets'],
['id' => 'account', 'label' => 'Gast'],
];
}
}

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Desktop;
final class SkinResolver
{
/**
* @return array<int, string>
*/
public static function all(): array
{
return ['windows', 'apple', 'linux'];
}
public static function resolve(?string $requestedSkin): string
{
$skin = strtolower((string) $requestedSkin);
return in_array($skin, self::all(), true) ? $skin : 'windows';
}
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%)',
};
}
}

View File

@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace Desktop;
final class WindowManager
{
public function __construct(
private readonly AppRegistry $registry,
) {
}
/**
* @return array<int, array<string, mixed>>
*/
public function defaultWindows(): array
{
$defaults = ['welcome-center', 'public-dashboard'];
$windows = [];
foreach ($defaults as $index => $appId) {
$app = $this->registry->find($appId);
if ($app === null) {
continue;
}
$windows[] = [
'window_id' => 'window-' . $appId,
'app_id' => $appId,
'title' => $app['title'],
'state' => $index === 0 ? 'focused' : 'open',
'x' => 72 + ($index * 48),
'y' => 84 + ($index * 36),
'width' => $app['default_width'] ?? 640,
'height' => $app['default_height'] ?? 420,
'content' => $app['summary'] ?? '',
];
}
return $windows;
}
}