nexus basic

This commit is contained in:
2026-06-04 22:07:25 +02:00
parent aa7ec1d321
commit 3c1cc30fe9
11 changed files with 1222 additions and 197 deletions

View File

@@ -3,202 +3,143 @@ declare(strict_types=1);
$auth = app()->auth();
$authUser = $auth->user();
$service = dashboards();
$ownerKey = auth_user_key();
$groups = auth_groups();
$service = dashboards();
$modules = array_values(array_filter(
$auth->filterModules(modules()->all()),
static fn (array $module): bool => !empty($module['enabled'])
));
$dashboardsList = [];
$pageModules = [];
$defaultDashboard = null;
$dashboardItems = [];
if ($authUser !== null && $service->available() && $ownerKey !== '') {
$defaultDashboard = $service->ensureDefaultDashboard($ownerKey, 'Mein Dashboard');
$dashboardsList = $service->listAccessibleDashboards($ownerKey, $groups);
$pageModules = $service->listPageModulesForOwner($ownerKey);
if ($defaultDashboard !== []) {
$dashboardItems = $service->listItems((int) ($defaultDashboard['id'] ?? 0));
}
$selectedDashboardId = (int) ($_GET['board'] ?? 0);
$currentDashboard = $service->available()
? $service->resolveHomeDashboard($ownerKey !== '' ? $ownerKey : null, $groups, $authUser !== null, $selectedDashboardId)
: null;
$dashboardItems = $currentDashboard !== null ? $service->listItems((int) ($currentDashboard['id'] ?? 0)) : [];
$accessibleApps = ($authUser !== null && $service->available()) ? $service->listApps($ownerKey, true) : [];
$appsById = [];
foreach ($accessibleApps as $appEntry) {
$appsById[(int) ($appEntry['id'] ?? 0)] = $appEntry;
}
$widgetTemplates = ($authUser !== null && $service->available()) ? $service->listWidgetTemplates($ownerKey, true) : [];
$widgetTemplatesById = [];
foreach ($widgetTemplates as $template) {
$widgetTemplatesById[(int) ($template['id'] ?? 0)] = $template;
}
$GLOBALS['layout_header_base_title'] = 'Nexus';
$GLOBALS['layout_header_title'] = 'Nexus';
$GLOBALS['layout_header_context'] = 'Übersicht';
$GLOBALS['layout_header_text'] = $authUser === null
? 'Zentraler Einstieg in Nexus und die verfügbaren Bereiche.'
: 'Persönliche Übersicht aus Dashboards, Seitenmodulen und klassischen Modulen.';
$GLOBALS['layout_header_context'] = $currentDashboard !== null ? (string) ($currentDashboard['title'] ?? 'Dashboard') : 'Dashboard';
$GLOBALS['layout_header_text'] = $currentDashboard !== null
? (string) ($currentDashboard['description'] ?? '')
: 'Kein öffentliches oder persönliches Home-Dashboard verfügbar.';
$renderBookmarks = static function (array $config): array {
$items = [];
$raw = trim((string) ($config['bookmarks'] ?? ''));
if ($raw === '') {
return [];
}
foreach (preg_split('/\r\n|\r|\n/', $raw) ?: [] as $line) {
$line = trim($line);
if ($line === '') {
continue;
}
[$label, $url] = array_pad(array_map('trim', explode('|', $line, 2)), 2, '');
if ($label !== '' && $url !== '') {
$items[] = ['label' => $label, 'url' => $url];
}
}
return $items;
};
?>
<div class="module-shell"><div class="module-page-bg"><div class="module-page-stack">
<?php if ($authUser !== null): ?>
<header class="module-hero submenu-box">
<div class="module-hero-top module-hero-top--compact">
<nav class="module-tabs" aria-label="Nexus Navigation">
<a class="module-button module-button--tab-active" href="/">Nexus Übersicht</a>
<a class="module-button module-button--tab" href="/dashboard">Dashboard</a>
<a class="module-button module-button--tab" href="/dashboards">Dashboards</a>
<a class="module-button module-button--tab" href="/integrations">Integrationen</a>
<a class="module-button module-button--tab" href="/page-modules">Seitenmodule</a>
<?php if (auth_is_admin()): ?>
<a class="module-button module-button--tab" href="/modules">Aktive Module</a>
<?php endif; ?>
</nav>
<div class="module-hero-actions module-submenu-actions">
<a class="module-button module-button--secondary module-button--small" href="/settings">Nexus Einstellungen</a>
</div>
</div>
</header>
<?php if ($currentDashboard === null): ?>
<section class="section-box">
<h2>Mein Standard-Dashboard</h2>
<p class="muted">Der schnellste Einstieg in deine wichtigsten Nexus-Inhalte.</p>
<?php if ($defaultDashboard === null || $defaultDashboard === []): ?>
<div class="dashboard-empty">Kein Dashboard verfügbar.</div>
<?php else: ?>
<div class="nexus-quick-grid">
<article class="card-box nexus-stat-card">
<span class="module-admin-meta__label">Dashboard</span>
<strong><?= e((string) ($defaultDashboard['title'] ?? 'Mein Dashboard')) ?></strong>
<p class="muted"><?= e((string) ($defaultDashboard['description'] ?? 'Persönliches Standard-Dashboard')) ?></p>
<a class="module-button module-button--secondary module-button--small" href="/dashboard?id=<?= (int) ($defaultDashboard['id'] ?? 0) ?>">Öffnen</a>
</article>
<article class="card-box nexus-stat-card">
<span class="module-admin-meta__label">Elemente</span>
<strong><?= count($dashboardItems) ?></strong>
<p class="muted">Aktive Dashboard-Elemente im Standard-Dashboard.</p>
</article>
<article class="card-box nexus-stat-card">
<span class="module-admin-meta__label">Seitenmodule</span>
<strong><?= count($pageModules) ?></strong>
<p class="muted">Eigene, on-the-fly angelegte Seitenmodule.</p>
</article>
<article class="card-box nexus-stat-card">
<span class="module-admin-meta__label">Klassische Module</span>
<strong><?= count($modules) ?></strong>
<p class="muted">Aktuell sichtbare, klassische Nexus-Module.</p>
</article>
</div>
<h2>Kein Home-Dashboard verfügbar</h2>
<p class="muted">Lege als Administrator ein öffentliches Dashboard fest oder richte dein persönliches Dashboard ein.</p>
<?php if ($authUser !== null): ?>
<a class="module-button module-button--secondary module-button--small" href="/dashboard">Zum Dashboard</a>
<?php endif; ?>
</section>
<?php elseif ($dashboardItems === []): ?>
<section class="section-box">
<h2>Dashboards</h2>
<p class="muted">Eigene und freigegebene Dashboards im globalen Nexus-System.</p>
<div class="module-admin-grid module-admin-grid--compact">
<?php foreach (array_slice($dashboardsList, 0, 6) as $dashboard): ?>
<article class="card-box module-admin-card">
<div class="module-admin-card__head">
<div class="module-admin-card__title">
<h2><?= e((string) ($dashboard['title'] ?? 'Dashboard')) ?></h2>
<p><?= e((string) ($dashboard['description'] ?? 'Flexible Dashboard-Fläche für Widgets und Seitenmodule.')) ?></p>
</div>
</div>
<div class="module-admin-meta">
<div class="module-admin-meta__item">
<span class="module-admin-meta__label">Sichtbarkeit</span>
<strong class="module-admin-badge"><?= e(ucfirst((string) ($dashboard['visibility'] ?? 'private'))) ?></strong>
</div>
</div>
<div class="module-admin-actions">
<a class="module-button module-button--secondary module-button--small" href="/dashboard?id=<?= (int) ($dashboard['id'] ?? 0) ?>">Öffnen</a>
</div>
</article>
<?php endforeach; ?>
</div>
</section>
<div class="module-admin-grid">
<article class="card-box module-admin-card">
<div class="module-admin-card__head">
<div class="module-admin-card__title">
<h2>Seitenmodule</h2>
<p>On-the-fly angelegte Zielseiten und eingebettete Tools.</p>
</div>
</div>
<div class="module-admin-meta">
<div class="module-admin-meta__item">
<span class="module-admin-meta__label">Anzahl</span>
<strong class="module-admin-badge module-admin-badge--success"><?= count($pageModules) ?></strong>
</div>
</div>
<div class="module-admin-actions">
<a class="module-button module-button--secondary module-button--small" href="/page-modules">Verwalten</a>
</div>
</article>
<article class="card-box module-admin-card">
<div class="module-admin-card__head">
<div class="module-admin-card__title">
<h2>Integrationen</h2>
<p>Zentrale Anbindungen an Home Assistant, Pi-hole, Proxmox und andere Systeme.</p>
</div>
</div>
<div class="module-admin-actions">
<a class="module-button module-button--secondary module-button--small" href="/integrations">Verwalten</a>
</div>
</article>
<article class="card-box module-admin-card">
<div class="module-admin-card__head">
<div class="module-admin-card__title">
<h2>Dashboards konfigurieren</h2>
<p>Eigene Dashboard-Flächen, Reihenfolge und Standard-Dashboard verwalten.</p>
</div>
</div>
<div class="module-admin-actions">
<a class="module-button module-button--secondary module-button--small" href="/dashboards">Öffnen</a>
</div>
</article>
</div>
<section class="section-box">
<h2>Klassische Module</h2>
<p class="muted">Die bisherigen Nexus-Module bleiben parallel zum neuen Grundgerüst bestehen.</p>
<div class="module-list">
<?php foreach ($modules as $module): ?>
<a class="module-row" href="<?= e((string) ($module['entry'] ?? ('/module/' . $module['name']))) ?>">
<span class="module-row__icon"><?= e(strtoupper(substr((string) ($module['title'] ?? $module['name']), 0, 1))) ?></span>
<span class="module-row__content">
<strong class="module-title"><?= e((string) ($module['title'] ?? $module['name'] ?? 'Modul')) ?></strong>
<span class="module-desc"><?= e((string) ($module['description'] ?? '')) ?></span>
</span>
</a>
<?php endforeach; ?>
</div>
<h2><?= e((string) ($currentDashboard['title'] ?? 'Dashboard')) ?></h2>
<p class="muted">Dieses Dashboard enthält noch keine Elemente.</p>
<?php if ($authUser !== null): ?>
<a class="module-button module-button--secondary module-button--small" href="/dashboard?id=<?= (int) ($currentDashboard['id'] ?? 0) ?>">Dashboard bearbeiten</a>
<?php endif; ?>
</section>
<?php else: ?>
<section class="section-box">
<h2>Nexus Einstieg</h2>
<p class="muted">Nach der Anmeldung stehen persönliche Dashboards, Integrationen und Seitenmodule bereit.</p>
<div class="module-admin-grid">
<article class="card-box module-admin-card">
<div class="module-admin-card__head">
<div class="module-admin-card__title">
<h2>Persönliche Dashboards</h2>
<p>Mehrere frei konfigurierbare Übersichten pro Benutzer.</p>
<div class="dashboard-grid">
<?php foreach ($dashboardItems as $item): ?>
<?php
$itemType = (string) ($item['item_type'] ?? 'link');
$config = is_array($item['config'] ?? null) ? $item['config'] : [];
if ($itemType === 'widget_template' && !empty($config['widget_template_id']) && isset($widgetTemplatesById[(int) $config['widget_template_id']])) {
$template = $widgetTemplatesById[(int) $config['widget_template_id']];
$itemType = (string) ($template['widget_type'] ?? $itemType);
$config = array_merge(is_array($template['config'] ?? null) ? $template['config'] : [], $config);
}
$columnSpan = max(1, min(4, (int) ($item['column_span'] ?? 1)));
$rowSpan = max(1, min(4, (int) ($item['row_span'] ?? 1)));
$gridStyles = 'grid-column: span ' . $columnSpan . '; grid-row: span ' . $rowSpan . ';';
if (!empty($item['grid_column'])) {
$gridStyles .= 'grid-column-start:' . (int) $item['grid_column'] . ';';
}
if (!empty($item['grid_row'])) {
$gridStyles .= 'grid-row-start:' . (int) $item['grid_row'] . ';';
}
$targetUrl = trim((string) ($config['url'] ?? ''));
$pageModule = null;
if ($itemType === 'page_module' && !empty($config['page_module_id'])) {
$pageModule = $service->getPageModule((int) $config['page_module_id'], $ownerKey, $groups);
$targetUrl = trim((string) ($pageModule['target_url'] ?? $targetUrl));
}
$appEntry = null;
if ($itemType === 'app' && !empty($config['app_id'])) {
$appEntry = $appsById[(int) $config['app_id']] ?? null;
$targetUrl = trim((string) ($appEntry['app_url'] ?? $targetUrl));
}
$bookmarks = $itemType === 'bookmark_group' ? $renderBookmarks($config) : [];
?>
<article class="card-box dashboard-widget" style="<?= e($gridStyles) ?>">
<div class="dashboard-widget__head">
<div>
<span class="module-admin-meta__label"><?= e(strtoupper(str_replace('_', ' ', $itemType))) ?></span>
<h2><?= e((string) ($item['title'] ?? 'Element')) ?></h2>
<?php if (!empty($item['description'])): ?>
<p><?= e((string) $item['description']) ?></p>
<?php endif; ?>
</div>
</div>
</article>
<article class="card-box module-admin-card">
<div class="module-admin-card__head">
<div class="module-admin-card__title">
<h2>Integrationen</h2>
<p>Zentrale Anbindungen für Fremdsysteme und externe Datenquellen.</p>
<?php if ($itemType === 'bookmark_group' && $bookmarks !== []): ?>
<div class="dashboard-links">
<?php foreach ($bookmarks as $bookmark): ?>
<a class="module-button module-button--secondary module-button--small" href="<?= e($bookmark['url']) ?>" target="_blank" rel="noreferrer"><?= e($bookmark['label']) ?></a>
<?php endforeach; ?>
</div>
</div>
</article>
<article class="card-box module-admin-card">
<div class="module-admin-card__head">
<div class="module-admin-card__title">
<h2>Seitenmodule</h2>
<p>On-the-fly angelegte Links und eingebettete Weboberflächen.</p>
<?php elseif (($itemType === 'iframe' || ($pageModule !== null && (string) ($pageModule['module_type'] ?? '') === 'iframe')) && $targetUrl !== ''): ?>
<iframe class="dashboard-widget__frame" src="<?= e($targetUrl) ?>" loading="lazy" referrerpolicy="no-referrer"></iframe>
<?php elseif ($appEntry !== null): ?>
<div class="dashboard-widget__meta">
<?php if (!empty($appEntry['icon_url'])): ?>
<img class="dashboard-app-icon" src="<?= e((string) $appEntry['icon_url']) ?>" alt="">
<?php endif; ?>
<p><?= e((string) ($appEntry['description'] ?? $targetUrl)) ?></p>
<a class="module-button module-button--secondary module-button--small" href="<?= e($targetUrl) ?>" target="_blank" rel="noreferrer">App öffnen</a>
</div>
</div>
<?php elseif ($pageModule !== null): ?>
<div class="dashboard-widget__meta">
<p><?= e((string) ($pageModule['description'] ?? 'Seitenmodul aus dem Nexus-System.')) ?></p>
<a class="module-button module-button--secondary module-button--small" href="/page-modules/view/<?= (int) ($pageModule['id'] ?? 0) ?>">Öffnen</a>
</div>
<?php elseif ($targetUrl !== ''): ?>
<div class="dashboard-widget__meta">
<p><?= e($targetUrl) ?></p>
<a class="module-button module-button--secondary module-button--small" href="<?= e($targetUrl) ?>" target="_blank" rel="noreferrer">Öffnen</a>
</div>
<?php else: ?>
<div class="dashboard-empty">Für dieses Element ist noch kein Inhalt hinterlegt.</div>
<?php endif; ?>
</article>
</div>
</section>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div></div></div>