144 lines
5.6 KiB
PHP
144 lines
5.6 KiB
PHP
<?php
|
|
/**
|
|
* Erwartet Variablen:
|
|
* - $category (string)
|
|
* - $items (array)
|
|
* - $serverStatusByUrl (array)
|
|
*/
|
|
|
|
// Hilfsfunktion: URLs für Status-Matching normalisieren (z.B. /nextcloud vs /nextcloud/)
|
|
$__normalize_status_url = static function (string $url): string {
|
|
$u = trim($url);
|
|
if ($u === '') return $u;
|
|
|
|
// Nur Trailing Slash entfernen (aber nicht bei "https://host/")
|
|
$parts = parse_url($u);
|
|
if (!is_array($parts) || empty($parts['scheme']) || empty($parts['host'])) {
|
|
return rtrim($u, '/');
|
|
}
|
|
|
|
$path = $parts['path'] ?? '';
|
|
if (is_string($path) && $path !== '' && $path !== '/') {
|
|
$parts['path'] = rtrim($path, '/');
|
|
if ($parts['path'] === '') {
|
|
$parts['path'] = '/';
|
|
}
|
|
}
|
|
|
|
$normalized = strtolower((string)$parts['scheme']) . '://' . (string)$parts['host'];
|
|
if (!empty($parts['port'])) {
|
|
$normalized .= ':' . (string)$parts['port'];
|
|
}
|
|
$normalized .= (string)($parts['path'] ?? '');
|
|
if (!empty($parts['query'])) {
|
|
$normalized .= '?' . (string)$parts['query'];
|
|
}
|
|
|
|
return $normalized;
|
|
};
|
|
|
|
// Normalisierte Map bauen (damit das Matching tolerant ist)
|
|
$__serverStatusByUrlNormalized = [];
|
|
foreach ($serverStatusByUrl as $__u => $__svc) {
|
|
if (is_string($__u)) {
|
|
$__serverStatusByUrlNormalized[$__normalize_status_url($__u)] = $__svc;
|
|
}
|
|
}
|
|
?>
|
|
<section>
|
|
<h2 class="category-title">
|
|
<?= htmlspecialchars(category_title((string)$category), ENT_QUOTES) ?>
|
|
</h2>
|
|
|
|
<div class="cards">
|
|
<?php foreach ($items as $project): ?>
|
|
<?php
|
|
// Optional: Status für dieses Projekt erkennen
|
|
$status = null;
|
|
$statusKey = null;
|
|
|
|
// Für JS-Update: eine kanonische Status-URL bestimmen
|
|
$statusUrl = null;
|
|
if (!empty($project['url']) && is_string($project['url'])) {
|
|
if (substr($project['url'], 0, 1) === '/') {
|
|
$statusUrl = $__normalize_status_url('https://fabianschieder.com' . $project['url']);
|
|
} else {
|
|
$statusUrl = $__normalize_status_url((string)$project['url']);
|
|
}
|
|
}
|
|
|
|
// 1) Externe absolute URL direkt matchen
|
|
if (!empty($project['url']) && isset($__serverStatusByUrlNormalized[$__normalize_status_url((string)$project['url'])])) {
|
|
$statusKey = $__normalize_status_url((string)$project['url']);
|
|
}
|
|
|
|
// 2) Interne Pfade (/git, /nextcloud) auf Domain mappen
|
|
if ($statusKey === null && !empty($project['url']) && is_string($project['url']) && substr($project['url'], 0, 1) === '/') {
|
|
$statusKeyCandidate = 'https://fabianschieder.com' . $project['url'];
|
|
$statusKeyCandidate = $__normalize_status_url($statusKeyCandidate);
|
|
if (isset($__serverStatusByUrlNormalized[$statusKeyCandidate])) {
|
|
$statusKey = $statusKeyCandidate;
|
|
}
|
|
}
|
|
|
|
if ($statusKey !== null) {
|
|
$status = $__serverStatusByUrlNormalized[$statusKey];
|
|
}
|
|
|
|
$state = $status ? (string)($status['state'] ?? 'unknown') : 'unknown';
|
|
$detail = $status && !empty($status['detail']) ? (string)$status['detail'] : '';
|
|
|
|
$badgeText = null;
|
|
if ($category !== 'dienste') {
|
|
$badgeText = 'Unbekannt';
|
|
if ($state === 'up') $badgeText = 'Online';
|
|
elseif ($state === 'down') $badgeText = 'Offline';
|
|
}
|
|
?>
|
|
|
|
<a
|
|
href="<?= htmlspecialchars((string)$project['url'], ENT_QUOTES) ?>"
|
|
class="card"
|
|
<?= !empty($project['external']) ? 'target="_blank" rel="noopener noreferrer"' : '' ?>
|
|
style="--accent: <?= htmlspecialchars((string)($project['color'] ?? '#6366f1'), ENT_QUOTES) ?>;"
|
|
<?= $statusUrl ? 'data-status-url="' . htmlspecialchars($statusUrl, ENT_QUOTES) . '"' : '' ?>
|
|
>
|
|
|
|
<div class="card-icon">
|
|
<?php if (!empty($project['logo'])): ?>
|
|
<img
|
|
src="<?= htmlspecialchars((string)$project['logo'], ENT_QUOTES) ?>"
|
|
alt="<?= htmlspecialchars((string)$project['title'], ENT_QUOTES) ?> Logo"
|
|
class="card-logo"
|
|
loading="lazy"
|
|
decoding="async"
|
|
>
|
|
<?php else: ?>
|
|
<span aria-hidden="true">📁</span>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="card-body">
|
|
<h3><?= htmlspecialchars((string)$project['title'], ENT_QUOTES) ?></h3>
|
|
<p>
|
|
<?= htmlspecialchars((string)$project['description'], ENT_QUOTES) ?>
|
|
</p>
|
|
</div>
|
|
|
|
<?php if ($badgeText !== null): ?>
|
|
<div class="status-right">
|
|
<span class="status-badge status-badge--<?= htmlspecialchars((string)$state, ENT_QUOTES) ?>"
|
|
data-status-badge="1"
|
|
title="<?= htmlspecialchars($detail !== '' ? $detail : (string)$badgeText, ENT_QUOTES) ?>">
|
|
<?= htmlspecialchars((string)$badgeText, ENT_QUOTES) ?>
|
|
</span>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="card-arrow" aria-hidden="true">→</div>
|
|
<?php endif; ?>
|
|
</a>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</section>
|
|
|