Dashboard
This commit is contained in:
@@ -563,3 +563,64 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dashboard-card-grid {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-programme-card {
|
||||||
|
text-align: left;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 64px 1fr;
|
||||||
|
gap: 0.75rem;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 0.85rem;
|
||||||
|
background: var(--panel-2);
|
||||||
|
color: var(--text);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-programme-card:hover {
|
||||||
|
background: var(--panel-3);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-programme-card img {
|
||||||
|
grid-row: span 3;
|
||||||
|
width: 64px;
|
||||||
|
height: 44px;
|
||||||
|
object-fit: contain;
|
||||||
|
background: var(--panel);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 0.6rem;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-programme-card strong {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-programme-card span {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.88rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-progress {
|
||||||
|
height: 8px;
|
||||||
|
background: var(--panel);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 999px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-progress div {
|
||||||
|
height: 100%;
|
||||||
|
background: var(--accent);
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export function initProgrammeModal() {
|
|||||||
document.body.classList.remove("modal-open");
|
document.body.classList.remove("modal-open");
|
||||||
};
|
};
|
||||||
|
|
||||||
document.querySelectorAll(".timeline-programme").forEach((programme) => {
|
document.querySelectorAll(".timeline-programme, .dashboard-programme").forEach((programme) => {
|
||||||
programme.addEventListener("click", () => openModal(programme));
|
programme.addEventListener("click", () => openModal(programme));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+125
-38
@@ -1,23 +1,53 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../src/Services/LogoService.php';
|
require_once __DIR__ . '/../src/Services/LogoService.php';
|
||||||
|
|
||||||
$now = new DateTimeImmutable('now', new DateTimeZone('Europe/Vienna'));
|
$tz = new DateTimeZone('Europe/Vienna');
|
||||||
|
$now = new DateTimeImmutable('now', $tz);
|
||||||
$upcoming = [];
|
$upcoming = [];
|
||||||
$primetime = [];
|
$primetime = [];
|
||||||
|
$programmeIndex = [];
|
||||||
|
|
||||||
|
function dashboardProgrammeId(string $channelId, mixed $start, mixed $title): string {
|
||||||
|
$startKey = $start instanceof DateTimeInterface ? $start->getTimestamp() : (string)$start;
|
||||||
|
return md5($channelId . '|' . $startKey . '|' . $title);
|
||||||
|
}
|
||||||
|
|
||||||
|
function dashboardAddProgrammeIndex(array &$programmeIndex, string $id, string $channelId, array $channel, array $p): void {
|
||||||
|
$metadata = $p['metadata'] ?? [];
|
||||||
|
|
||||||
|
$programmeIndex[$id] = [
|
||||||
|
'id' => $id,
|
||||||
|
'channel_id' => $channelId,
|
||||||
|
'channel' => $channel['name'] ?? $channelId,
|
||||||
|
'channel_number' => $channel['number'] ?? 999999,
|
||||||
|
'favorite' => $channel['favorite'] ?? false,
|
||||||
|
'title' => $p['title'] ?? '',
|
||||||
|
'subtitle' => $p['subtitle'] ?? '',
|
||||||
|
'description' => $p['desc'] ?? $p['description'] ?? '',
|
||||||
|
'category' => $p['category'] ?? '',
|
||||||
|
'metadata' => $metadata,
|
||||||
|
'year' => $metadata['year'] ?? '',
|
||||||
|
'rating' => $metadata['age_rating'] ?? '',
|
||||||
|
'country' => $metadata['country'] ?? '',
|
||||||
|
'start' => $p['start'] instanceof DateTimeInterface ? $p['start']->format('H:i') : date('H:i', (int)($p['start'] ?? 0)),
|
||||||
|
'stop' => $p['stop'] instanceof DateTimeInterface ? $p['stop']->format('H:i') : date('H:i', (int)($p['stop'] ?? 0)),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($programmes as $channelId => $items) {
|
foreach ($programmes as $channelId => $items) {
|
||||||
$channel = $channels[$channelId] ?? null;
|
$channel = $channels[$channelId] ?? null;
|
||||||
|
if (!$channel) continue;
|
||||||
if (!$channel) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($items as $p) {
|
foreach ($items as $p) {
|
||||||
$start = $p['start'];
|
$start = $p['start'];
|
||||||
$stop = $p['stop'];
|
if (!$start instanceof DateTimeInterface) continue;
|
||||||
|
|
||||||
if ($start >= $now && $start <= $now->modify('+30 minutes')) {
|
if ($start >= $now && $start <= $now->modify('+30 minutes')) {
|
||||||
|
$id = dashboardProgrammeId($channelId, $start, $p['title'] ?? '');
|
||||||
|
dashboardAddProgrammeIndex($programmeIndex, $id, $channelId, $channel, $p);
|
||||||
|
|
||||||
$upcoming[] = [
|
$upcoming[] = [
|
||||||
|
'id' => $id,
|
||||||
'channel_id' => $channelId,
|
'channel_id' => $channelId,
|
||||||
'channel' => $channel,
|
'channel' => $channel,
|
||||||
'programme' => $p,
|
'programme' => $p,
|
||||||
@@ -27,7 +57,11 @@ foreach ($programmes as $channelId => $items) {
|
|||||||
if ($start->format('Y-m-d') === $now->format('Y-m-d')
|
if ($start->format('Y-m-d') === $now->format('Y-m-d')
|
||||||
&& $start->format('H:i') >= '20:00'
|
&& $start->format('H:i') >= '20:00'
|
||||||
&& $start->format('H:i') <= '23:00') {
|
&& $start->format('H:i') <= '23:00') {
|
||||||
|
$id = dashboardProgrammeId($channelId, $start, $p['title'] ?? '');
|
||||||
|
dashboardAddProgrammeIndex($programmeIndex, $id, $channelId, $channel, $p);
|
||||||
|
|
||||||
$primetime[] = [
|
$primetime[] = [
|
||||||
|
'id' => $id,
|
||||||
'channel_id' => $channelId,
|
'channel_id' => $channelId,
|
||||||
'channel' => $channel,
|
'channel' => $channel,
|
||||||
'programme' => $p,
|
'programme' => $p,
|
||||||
@@ -36,13 +70,32 @@ foreach ($programmes as $channelId => $items) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($currentProgrammes as $item) {
|
||||||
|
$id = dashboardProgrammeId($item['channel_id'], $item['start'], $item['title'] ?? '');
|
||||||
|
|
||||||
|
$programmeIndex[$id] = [
|
||||||
|
'id' => $id,
|
||||||
|
'channel_id' => $item['channel_id'],
|
||||||
|
'channel' => $item['channel_name'],
|
||||||
|
'channel_number' => $item['channel_number'],
|
||||||
|
'favorite' => $item['favorite'],
|
||||||
|
'title' => $item['title'],
|
||||||
|
'subtitle' => $item['subtitle'],
|
||||||
|
'description' => $item['description'],
|
||||||
|
'category' => $item['category'],
|
||||||
|
'metadata' => $item['metadata'] ?? [],
|
||||||
|
'year' => $item['year'] ?? '',
|
||||||
|
'rating' => $item['rating'] ?? '',
|
||||||
|
'country' => $item['country'] ?? '',
|
||||||
|
'start' => date('H:i', $item['start']),
|
||||||
|
'stop' => date('H:i', $item['stop']),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
usort($upcoming, fn($a, $b) => $a['programme']['start'] <=> $b['programme']['start']);
|
usort($upcoming, fn($a, $b) => $a['programme']['start'] <=> $b['programme']['start']);
|
||||||
usort($primetime, fn($a, $b) => $a['programme']['start'] <=> $b['programme']['start']);
|
usort($primetime, fn($a, $b) => $a['programme']['start'] <=> $b['programme']['start']);
|
||||||
|
|
||||||
$favoritesNow = array_values(array_filter(
|
$favoritesNow = array_values(array_filter($currentProgrammes, fn($item) => !empty($item['favorite'])));
|
||||||
$currentProgrammes,
|
|
||||||
fn($item) => !empty($item['favorite'])
|
|
||||||
));
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<section class="dashboard-hero">
|
<section class="dashboard-hero">
|
||||||
@@ -57,29 +110,33 @@ $favoritesNow = array_values(array_filter(
|
|||||||
<section class="dashboard-panel">
|
<section class="dashboard-panel">
|
||||||
<h3>🔥 Jetzt läuft</h3>
|
<h3>🔥 Jetzt läuft</h3>
|
||||||
|
|
||||||
<?php foreach (array_slice($currentProgrammes, 0, 6) as $item): ?>
|
<div class="dashboard-card-grid">
|
||||||
<a class="dashboard-item" href="/?view=now">
|
<?php foreach (array_slice($currentProgrammes, 0, 6) as $item): ?>
|
||||||
<img src="<?= htmlspecialchars(LogoService::getLogoUrl($item['channel_id'])) ?>" alt="">
|
<?php $id = dashboardProgrammeId($item['channel_id'], $item['start'], $item['title'] ?? ''); ?>
|
||||||
<div>
|
<button class="dashboard-programme-card dashboard-programme" type="button" data-programme-id="<?= htmlspecialchars($id) ?>">
|
||||||
|
<img src="<?= htmlspecialchars(LogoService::getLogoUrl($item['channel_id'])) ?>" alt="">
|
||||||
<strong><?= htmlspecialchars($item['title']) ?></strong>
|
<strong><?= htmlspecialchars($item['title']) ?></strong>
|
||||||
<span><?= htmlspecialchars($item['channel_name']) ?> · noch <?= (int)$item['remaining_minutes'] ?> Min.</span>
|
<span><?= htmlspecialchars($item['channel_name']) ?> · noch <?= (int)$item['remaining_minutes'] ?> Min.</span>
|
||||||
</div>
|
<div class="dashboard-progress">
|
||||||
</a>
|
<div style="width: <?= (int)$item['percent'] ?>%"></div>
|
||||||
<?php endforeach; ?>
|
</div>
|
||||||
|
</button>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="dashboard-panel">
|
<section class="dashboard-panel">
|
||||||
<h3>⏰ Beginnt gleich</h3>
|
<h3>⏰ Beginnt gleich</h3>
|
||||||
|
|
||||||
<?php foreach (array_slice($upcoming, 0, 6) as $item): ?>
|
<div class="dashboard-card-grid">
|
||||||
<a class="dashboard-item" href="/?view=day">
|
<?php foreach (array_slice($upcoming, 0, 6) as $item): ?>
|
||||||
<img src="<?= htmlspecialchars(LogoService::getLogoUrl($item['channel_id'])) ?>" alt="">
|
<button class="dashboard-programme-card dashboard-programme" type="button" data-programme-id="<?= htmlspecialchars($item['id']) ?>">
|
||||||
<div>
|
<img src="<?= htmlspecialchars(LogoService::getLogoUrl($item['channel_id'])) ?>" alt="">
|
||||||
<strong><?= htmlspecialchars($item['programme']['title']) ?></strong>
|
<strong><?= htmlspecialchars($item['programme']['title']) ?></strong>
|
||||||
<span><?= $item['programme']['start']->format('H:i') ?> · <?= htmlspecialchars($item['channel']['name']) ?></span>
|
<span><?= $item['programme']['start']->format('H:i') ?> · <?= htmlspecialchars($item['channel']['name']) ?></span>
|
||||||
</div>
|
</button>
|
||||||
</a>
|
<?php endforeach; ?>
|
||||||
<?php endforeach; ?>
|
</div>
|
||||||
|
|
||||||
<?php if (!$upcoming): ?>
|
<?php if (!$upcoming): ?>
|
||||||
<div class="empty compact">In den nächsten 30 Minuten beginnt keine Sendung.</div>
|
<div class="empty compact">In den nächsten 30 Minuten beginnt keine Sendung.</div>
|
||||||
@@ -89,15 +146,19 @@ $favoritesNow = array_values(array_filter(
|
|||||||
<section class="dashboard-panel">
|
<section class="dashboard-panel">
|
||||||
<h3>⭐ Favoriten jetzt</h3>
|
<h3>⭐ Favoriten jetzt</h3>
|
||||||
|
|
||||||
<?php foreach (array_slice($favoritesNow, 0, 6) as $item): ?>
|
<div class="dashboard-card-grid">
|
||||||
<a class="dashboard-item" href="/?view=favorites">
|
<?php foreach (array_slice($favoritesNow, 0, 6) as $item): ?>
|
||||||
<img src="<?= htmlspecialchars(LogoService::getLogoUrl($item['channel_id'])) ?>" alt="">
|
<?php $id = dashboardProgrammeId($item['channel_id'], $item['start'], $item['title'] ?? ''); ?>
|
||||||
<div>
|
<button class="dashboard-programme-card dashboard-programme" type="button" data-programme-id="<?= htmlspecialchars($id) ?>">
|
||||||
|
<img src="<?= htmlspecialchars(LogoService::getLogoUrl($item['channel_id'])) ?>" alt="">
|
||||||
<strong><?= htmlspecialchars($item['title']) ?></strong>
|
<strong><?= htmlspecialchars($item['title']) ?></strong>
|
||||||
<span><?= htmlspecialchars($item['channel_name']) ?> · <?= (int)$item['percent'] ?>%</span>
|
<span><?= htmlspecialchars($item['channel_name']) ?> · <?= (int)$item['percent'] ?>%</span>
|
||||||
</div>
|
<div class="dashboard-progress">
|
||||||
</a>
|
<div style="width: <?= (int)$item['percent'] ?>%"></div>
|
||||||
<?php endforeach; ?>
|
</div>
|
||||||
|
</button>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
<?php if (!$favoritesNow): ?>
|
<?php if (!$favoritesNow): ?>
|
||||||
<div class="empty compact">Aktuell läuft auf deinen Favoriten nichts.</div>
|
<div class="empty compact">Aktuell läuft auf deinen Favoriten nichts.</div>
|
||||||
@@ -107,18 +168,44 @@ $favoritesNow = array_values(array_filter(
|
|||||||
<section class="dashboard-panel">
|
<section class="dashboard-panel">
|
||||||
<h3>📺 Heute Abend</h3>
|
<h3>📺 Heute Abend</h3>
|
||||||
|
|
||||||
<?php foreach (array_slice($primetime, 0, 8) as $item): ?>
|
<div class="dashboard-card-grid">
|
||||||
<a class="dashboard-item" href="/?view=day">
|
<?php foreach (array_slice($primetime, 0, 8) as $item): ?>
|
||||||
<img src="<?= htmlspecialchars(LogoService::getLogoUrl($item['channel_id'])) ?>" alt="">
|
<button class="dashboard-programme-card dashboard-programme" type="button" data-programme-id="<?= htmlspecialchars($item['id']) ?>">
|
||||||
<div>
|
<img src="<?= htmlspecialchars(LogoService::getLogoUrl($item['channel_id'])) ?>" alt="">
|
||||||
<strong><?= htmlspecialchars($item['programme']['title']) ?></strong>
|
<strong><?= htmlspecialchars($item['programme']['title']) ?></strong>
|
||||||
<span><?= $item['programme']['start']->format('H:i') ?> · <?= htmlspecialchars($item['channel']['name']) ?></span>
|
<span><?= $item['programme']['start']->format('H:i') ?> · <?= htmlspecialchars($item['channel']['name']) ?></span>
|
||||||
</div>
|
</button>
|
||||||
</a>
|
<?php endforeach; ?>
|
||||||
<?php endforeach; ?>
|
</div>
|
||||||
|
|
||||||
<?php if (!$primetime): ?>
|
<?php if (!$primetime): ?>
|
||||||
<div class="empty compact">Für heute Abend wurden keine Sendungen gefunden.</div>
|
<div class="empty compact">Für heute Abend wurden keine Sendungen gefunden.</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.TVGUIDE_PROGRAMMES = <?= json_encode($programmeIndex, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="programme-modal" id="programmeModal" hidden>
|
||||||
|
<div class="programme-modal-backdrop" data-modal-close></div>
|
||||||
|
|
||||||
|
<div class="programme-modal-card">
|
||||||
|
<button class="programme-modal-close" type="button" data-modal-close>×</button>
|
||||||
|
|
||||||
|
<div class="programme-modal-header">
|
||||||
|
<img id="modalLogo" class="programme-modal-logo" src="/assets/logos/default.svg" alt="">
|
||||||
|
<div class="programme-modal-channel">
|
||||||
|
<div id="modalChannel"></div>
|
||||||
|
<div id="modalTime" class="programme-modal-time"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 id="modalTitle"></h2>
|
||||||
|
<div id="modalSubtitle" class="programme-modal-subtitle"></div>
|
||||||
|
<div id="modalCategory" class="programme-modal-category"></div>
|
||||||
|
<div id="modalMeta" class="programme-modal-meta"></div>
|
||||||
|
<p id="modalDescription"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user