aa31507ff5
"<- Dashboard" used href="?", which resolves to the current path with an empty query -- manage.php -- so it reloaded the manage page instead of returning to the feed. Point it at index.php.
199 lines
11 KiB
PHP
199 lines
11 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\View;
|
|
|
|
/** @var array<string, mixed> $config */
|
|
/** @var App\ManageAuth $auth */
|
|
/** @var array<int, array<string, mixed>> $feeds */
|
|
/** @var array{type: string, text: string}|null $flash */
|
|
|
|
$csrf = View::e($auth->csrfToken());
|
|
|
|
$feedGroups = [];
|
|
foreach ($feeds as $feed) {
|
|
$feedGroups[(string) $feed['source']][] = $feed;
|
|
}
|
|
|
|
$actionUrl = 'manage.php';
|
|
?>
|
|
<!doctype html>
|
|
<html lang="en" data-bs-theme="light">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Manage feeds · RSS Feed Dashboard</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=Plus+Jakarta+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap"
|
|
rel="stylesheet">
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
|
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
|
<link href="assets/style.css" rel="stylesheet">
|
|
</head>
|
|
<body class="app-body">
|
|
<header class="site-header">
|
|
<div class="container-xxl d-flex align-items-center justify-content-between gap-3 py-3">
|
|
<a class="brand" href="manage.php">
|
|
<span class="brand-mark" aria-hidden="true"></span>
|
|
<span class="brand-text">RSS <em>Feed</em> Dashboard</span>
|
|
</a>
|
|
<div class="d-flex align-items-center gap-3">
|
|
<span class="mono manage-title">Manage feeds</span>
|
|
<a class="manage-link" href="index.php">← Dashboard</a>
|
|
</div>
|
|
</div>
|
|
<div class="spectrum-rail" aria-hidden="true"></div>
|
|
</header>
|
|
|
|
<main class="container-xxl py-4 manage-main">
|
|
<?php if (!$auth->enabled()): ?>
|
|
<div class="manage-panel manage-notice">
|
|
<h1 class="manage-heading">Management is disabled</h1>
|
|
<p class="mb-0">
|
|
Set <code class="mono">manage_password</code> in <code class="mono">config/app.php</code>
|
|
to enable this page.
|
|
</p>
|
|
</div>
|
|
<?php elseif (!$auth->authed()): ?>
|
|
<?php if ($flash !== null): ?>
|
|
<div class="alert alert-soft alert-dismissible fade show small" role="alert">
|
|
<?= View::e($flash['text']) ?>
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
<?php endif; ?>
|
|
<div class="manage-panel manage-login">
|
|
<h1 class="manage-heading">Sign in to manage feeds</h1>
|
|
<p class="text-body-secondary small">This page configures which subreddits and YouTube channels the dashboard follows.</p>
|
|
<form method="post" action="<?= View::e($actionUrl) ?>" class="d-flex gap-2">
|
|
<input type="hidden" name="csrf" value="<?= $csrf ?>">
|
|
<input type="hidden" name="action" value="login">
|
|
<input type="password" name="input" class="form-control mono" placeholder="Password" required autofocus autocomplete="current-password">
|
|
<button type="submit" class="btn btn-energy btn-compact">Sign in</button>
|
|
</form>
|
|
</div>
|
|
<?php else: ?>
|
|
<?php if ($flash !== null): ?>
|
|
<div class="alert alert-dismissible fade show small <?= $flash['type'] === 'ok' ? 'alert-ok-soft' : 'alert-soft' ?>" role="alert">
|
|
<?= View::e($flash['text']) ?>
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="row g-4 mb-4">
|
|
<div class="col-12 col-lg-6">
|
|
<div class="manage-panel">
|
|
<h2 class="manage-subheading">Add a subreddit</h2>
|
|
<form method="post" action="<?= View::e($actionUrl) ?>" class="d-flex gap-2">
|
|
<input type="hidden" name="csrf" value="<?= $csrf ?>">
|
|
<input type="hidden" name="action" value="add_reddit">
|
|
<input type="text" name="input" class="form-control mono" inputmode="url"
|
|
placeholder="r/homelab · homelab · reddit.com/r/homelab"
|
|
required maxlength="300" autocomplete="off">
|
|
<button type="submit" class="btn btn-energy btn-compact">Add</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<div class="col-12 col-lg-6">
|
|
<div class="manage-panel">
|
|
<h2 class="manage-subheading">Add a YouTube channel</h2>
|
|
<form method="post" action="<?= View::e($actionUrl) ?>" class="d-flex gap-2">
|
|
<input type="hidden" name="csrf" value="<?= $csrf ?>">
|
|
<input type="hidden" name="action" value="add_youtube">
|
|
<input type="text" name="input" class="form-control mono" inputmode="url"
|
|
placeholder="@handle · UC… channel ID · channel URL"
|
|
required maxlength="300" autocomplete="off">
|
|
<button type="submit" class="btn btn-energy btn-compact">Add</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php if ($feedGroups === []): ?>
|
|
<div class="manage-panel manage-notice">
|
|
<p class="mb-0">No feeds registered yet — add one above, or edit <code class="mono">config/feeds.php</code>.</p>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php foreach ($feedGroups as $source => $groupFeeds): ?>
|
|
<section class="manage-group">
|
|
<h2 class="manage-group-title" style="--src: <?= View::e(View::sourceColor($source)) ?>">
|
|
<span class="pill-dot" aria-hidden="true"></span>
|
|
<?= View::e(View::sourceLabel($source)) ?>
|
|
<span class="mono count"><?= count($groupFeeds) ?></span>
|
|
</h2>
|
|
|
|
<div class="feed-rows">
|
|
<?php foreach ($groupFeeds as $feed): ?>
|
|
<?php
|
|
$url = (string) $feed['url'];
|
|
$label = (string) ($feed['label'] ?? $url);
|
|
$isEnabled = (int) $feed['enabled'] === 1;
|
|
$isConfig = (string) $feed['origin'] === 'config';
|
|
$lastError = $feed['last_error'] ?? null;
|
|
$lastSuccess = $feed['last_success_at'] ?? null;
|
|
$confirm = $isConfig
|
|
? sprintf('Hide "%s" from the dashboard? Its cached stories are kept.', $label)
|
|
: sprintf('Remove "%s"? Its cached stories stay hidden until it is added again.', $label);
|
|
?>
|
|
<div class="feed-row <?= $isEnabled ? '' : 'is-off' ?>" style="--src: <?= View::e(View::sourceColor($source)) ?>">
|
|
<div class="feed-row-main">
|
|
<span class="feed-row-label"><?= View::e($label) ?></span>
|
|
<span class="origin-badge mono"><?= $isConfig ? 'config' : 'manual' ?></span>
|
|
<a class="feed-row-url mono text-truncate" href="<?= View::e($url) ?>"
|
|
target="_blank" rel="noopener noreferrer"><?= View::e($url) ?></a>
|
|
<?php if (is_string($lastError) && $lastError !== ''): ?>
|
|
<span class="health health-err mono" title="<?= View::e($lastError) ?>">
|
|
<span class="health-dot" aria-hidden="true"></span>failed
|
|
</span>
|
|
<?php elseif (is_string($lastSuccess) && $lastSuccess !== ''): ?>
|
|
<span class="health health-ok mono" title="Last success: <?= View::e($lastSuccess) ?>">
|
|
<span class="health-dot" aria-hidden="true"></span><?= View::e(View::timeAgo($lastSuccess)) ?>
|
|
</span>
|
|
<?php else: ?>
|
|
<span class="health health-idle mono"><span class="health-dot" aria-hidden="true"></span>not fetched yet</span>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="feed-row-actions">
|
|
<form method="post" action="<?= View::e($actionUrl) ?>">
|
|
<input type="hidden" name="csrf" value="<?= $csrf ?>">
|
|
<input type="hidden" name="action" value="toggle">
|
|
<input type="hidden" name="url" value="<?= View::e($url) ?>">
|
|
<input type="hidden" name="enabled" value="<?= $isEnabled ? '0' : '1' ?>">
|
|
<button type="submit" class="btn btn-mini <?= $isEnabled ? '' : 'btn-mini-on' ?>">
|
|
<?= $isEnabled ? 'Disable' : 'Enable' ?>
|
|
</button>
|
|
</form>
|
|
<form method="post" action="<?= View::e($actionUrl) ?>"
|
|
data-confirm="<?= View::e($confirm) ?>">
|
|
<input type="hidden" name="csrf" value="<?= $csrf ?>">
|
|
<input type="hidden" name="action" value="remove">
|
|
<input type="hidden" name="url" value="<?= View::e($url) ?>">
|
|
<button type="submit" class="btn btn-mini btn-mini-danger">
|
|
<?= $isConfig ? 'Hide' : 'Remove' ?>
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</section>
|
|
<?php endforeach; ?>
|
|
|
|
<div class="d-flex justify-content-end mt-4">
|
|
<form method="post" action="<?= View::e($actionUrl) ?>">
|
|
<input type="hidden" name="csrf" value="<?= $csrf ?>">
|
|
<input type="hidden" name="action" value="logout">
|
|
<button type="submit" class="btn btn-mini">Sign out</button>
|
|
</form>
|
|
</div>
|
|
<?php endif; ?>
|
|
</main>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
|
|
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhykGkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
|
<script src="assets/manage.js" defer></script>
|
|
</body>
|
|
</html>
|