This commit is contained in:
Ty Clifford
2026-06-24 09:19:08 -04:00
commit 5f7c62f8a7
151 changed files with 18705 additions and 0 deletions
+219
View File
@@ -0,0 +1,219 @@
<?php
require_once __DIR__ . '/auth.php';
require_once __DIR__ . '/../includes/layout.php';
admin_require_auth();
$msg = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? 'settings';
if ($action === 'settings') {
$per_page = max(1, min(50, (int)($_POST['catalogue_per_page'] ?? 10)));
$site_title = trim($_POST['site_title'] ?? 'Ty Clifford');
$site_sub = trim($_POST['site_sub'] ?? 'tyclifford.com / media');
set_setting('catalogue_per_page', (string)$per_page);
set_setting('site_title', $site_title);
set_setting('site_sub', $site_sub);
$msg = 'Settings saved.';
}
if ($action === 'change_password') {
$current = $_POST['current_password'] ?? '';
$new1 = $_POST['new_password'] ?? '';
$new2 = $_POST['new_password2'] ?? '';
if (!password_verify($current, setting('admin_password'))) {
$msg = 'ERROR: Current password is incorrect.';
} elseif (strlen($new1) < 6) {
$msg = 'ERROR: New password must be at least 6 characters.';
} elseif ($new1 !== $new2) {
$msg = 'ERROR: New passwords do not match.';
} else {
set_setting('admin_password', password_hash($new1, PASSWORD_DEFAULT));
$msg = 'Password changed successfully.';
}
}
}
$per_page = setting('catalogue_per_page', '10');
$site_title = setting('site_title', 'Ty Clifford');
$site_sub = setting('site_sub', 'tyclifford.com / media');
// DB stats
$db = get_db();
$total_videos = $db->query("SELECT COUNT(*) FROM videos")->fetchColumn();
$total_sources = $db->query("SELECT COUNT(*) FROM video_sources")->fetchColumn();
$db_size = file_exists(DB_PATH) ? round(filesize(DB_PATH)/1024, 1) : 0;
$media_size = 0;
if (is_dir(MEDIA_DIR)) {
$iter = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(MEDIA_DIR, FilesystemIterator::SKIP_DOTS));
foreach ($iter as $f) $media_size += $f->getSize();
$media_size = round($media_size / 1048576, 1);
}
$msg_type = str_starts_with($msg, 'ERROR') ? 'error' : 'success';
render_head('Settings — Admin', '
.admin-layout { display:grid; grid-template-columns:1fr; gap:1.5rem; }
@media(min-width:900px) { .admin-layout { grid-template-columns:220px 1fr; } }
.admin-nav { background:var(--surface); border:1px solid var(--border); border-radius:calc(var(--r)+2px); padding:1.2rem; display:flex; flex-direction:column; gap:.4rem; align-self:start; position:sticky; top:1rem; }
.admin-nav-label { font-family:"Share Tech Mono",monospace; font-size:.58rem; letter-spacing:.18em; text-transform:uppercase; color:var(--text-3); margin-bottom:.3rem; padding-left:.5rem; }
.admin-nav a { display:flex; align-items:center; gap:.6rem; padding:.55rem .75rem; border-radius:var(--r); font-size:.82rem; color:var(--text-2); text-decoration:none; transition:background .15s,color .15s; }
.admin-nav a:hover { background:rgba(255,255,255,.05); color:var(--text); }
.admin-nav a.active { background:rgba(176,96,255,.12); color:var(--purple); }
.nav-divider { border:none; border-top:1px solid var(--border); margin:.4rem 0; }
.form-grid { display:grid; grid-template-columns:1fr; gap:1rem; }
@media(min-width:600px) { .form-grid { grid-template-columns:1fr 1fr; } }
.section-heading { font-family:"Share Tech Mono",monospace; font-size:.65rem; letter-spacing:.15em; text-transform:uppercase; color:var(--text-3); margin-bottom:.75rem; }
.hint { font-size:.72rem; color:var(--text-3); margin-top:.2rem; }
.stat-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(130px,1fr)); gap:.75rem; }
.stat-tile { background:var(--surface-2); border:1px solid var(--border); border-radius:var(--r); padding:1rem; display:flex; flex-direction:column; gap:.3rem; }
.stat-val { font-family:"Share Tech Mono",monospace; font-size:1.4rem; color:var(--text); font-weight:700; }
.stat-label{ font-family:"Share Tech Mono",monospace; font-size:.6rem; letter-spacing:.1em; text-transform:uppercase; color:var(--text-3); }
');
?>
<main class="page" role="main">
<header class="topbar">
<div class="topbar-brand">
<div>
<div class="brand-name">Ty Clifford</div>
<div class="brand-sub">admin / settings</div>
</div>
</div>
<nav class="topbar-social">
<a class="social-pill" href="../index.php" target="_blank">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"/><polyline points="15,3 21,3 21,9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
View Site
</a>
<a class="social-pill" href="logout.php">Logout</a>
</nav>
</header>
<?php if ($msg): ?>
<div class="notice notice-<?= $msg_type ?>"><?= h($msg) ?></div>
<?php endif; ?>
<div class="admin-layout">
<aside class="admin-nav">
<div class="admin-nav-label">Navigation</div>
<a href="index.php">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
Videos
</a>
<a href="add.php">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="16"/><line x1="8" y1="12" x2="16" y2="12"/></svg>
Add Video
</a>
<hr class="nav-divider">
<a href="settings.php" class="active">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.07 4.93l-1.41 1.41M4.93 4.93l1.41 1.41M19.07 19.07l-1.41-1.41M4.93 19.07l1.41-1.41M12 2v2M12 20v2M2 12h2M20 12h2"/></svg>
Settings
</a>
</aside>
<div style="display:flex;flex-direction:column;gap:1.25rem;">
<!-- Stats -->
<div class="card">
<p class="section-heading">Overview</p>
<div class="stat-grid">
<div class="stat-tile">
<span class="stat-val"><?= $total_videos ?></span>
<span class="stat-label">Videos</span>
</div>
<div class="stat-tile">
<span class="stat-val"><?= $total_sources ?></span>
<span class="stat-label">Source Files</span>
</div>
<div class="stat-tile">
<span class="stat-val"><?= $db_size ?> KB</span>
<span class="stat-label">Database</span>
</div>
<div class="stat-tile">
<span class="stat-val"><?= $media_size ?> MB</span>
<span class="stat-label">Media Storage</span>
</div>
</div>
</div>
<!-- General settings -->
<div class="card">
<p class="section-heading">General Settings</p>
<form method="post" action="settings.php">
<input type="hidden" name="action" value="settings">
<div class="form-grid" style="margin-bottom:1rem;">
<div class="form-group">
<label class="form-label" for="site_title">Site Title</label>
<input class="form-input" type="text" id="site_title" name="site_title"
value="<?= h($site_title) ?>">
</div>
<div class="form-group">
<label class="form-label" for="site_sub">Site Subtitle</label>
<input class="form-input" type="text" id="site_sub" name="site_sub"
value="<?= h($site_sub) ?>">
</div>
<div class="form-group">
<label class="form-label" for="catalogue_per_page">Videos per page</label>
<input class="form-input" type="number" id="catalogue_per_page"
name="catalogue_per_page" value="<?= h($per_page) ?>" min="1" max="50">
<span class="hint">How many thumbnails to show per page (150).</span>
</div>
</div>
<button class="btn btn-primary btn-sm" type="submit">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 21H5a2 2 0 01-2-2V5a2 2 0 012-2h11l5 5v11a2 2 0 01-2 2z"/><polyline points="17,21 17,13 7,13 7,21"/><polyline points="7,3 7,8 15,8"/></svg>
Save Settings
</button>
</form>
</div>
<!-- Change password -->
<div class="card">
<p class="section-heading">Change Password</p>
<form method="post" action="settings.php">
<input type="hidden" name="action" value="change_password">
<div class="form-grid" style="margin-bottom:1rem;">
<div class="form-group">
<label class="form-label" for="current_password">Current Password</label>
<input class="form-input" type="password" id="current_password" name="current_password"
autocomplete="current-password">
</div>
<div></div>
<div class="form-group">
<label class="form-label" for="new_password">New Password</label>
<input class="form-input" type="password" id="new_password" name="new_password"
autocomplete="new-password" minlength="6">
<span class="hint">Minimum 6 characters.</span>
</div>
<div class="form-group">
<label class="form-label" for="new_password2">Confirm New Password</label>
<input class="form-input" type="password" id="new_password2" name="new_password2"
autocomplete="new-password">
</div>
</div>
<button class="btn btn-secondary btn-sm" type="submit">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg>
Change Password
</button>
</form>
</div>
<!-- File locations reference -->
<div class="card">
<p class="section-heading">File Locations</p>
<div style="display:flex;flex-direction:column;gap:.5rem;font-family:'Share Tech Mono',monospace;font-size:.7rem;color:var(--text-3);">
<div><span style="color:var(--text-2);">Database:</span> data/media.db</div>
<div><span style="color:var(--text-2);">Videos:</span> media/videos/</div>
<div><span style="color:var(--text-2);">Thumbnails:</span> media/thumbs/</div>
<div><span style="color:var(--text-2);">Default password:</span> <span style="color:var(--red);">admin</span> — change immediately!</div>
</div>
</div>
</div>
</div>
<?php render_footer(); ?>
</main>
</body>
</html>