Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/treetrek.git

Restores navigation

Author Dave Jarvis <email>
Date 2026-02-08 17:50:24 GMT-0800
Commit 6f4d8a06135cbaf0c0d6d287c8d28e8a5d0139fe
Parent 6550908
new/Router.php
<?php
-require_once 'Page.php';
-require_once 'Views.php'; // Contains the Page implementations
+require_once 'Views.php';
class Router {
$reqRepo = $_GET['repo'] ?? '';
$action = $_GET['action'] ?? 'home';
-
- // Sanitize within the boundary of the Router
$hash = $this->sanitizePath($_GET['hash'] ?? '');
- // Find the repository
+ // Find the specific repository object
$currentRepo = null;
$decoded = urldecode($reqRepo);
foreach ($this->repositories as $repo) {
if ($repo['safe_name'] === $reqRepo || $repo['name'] === $decoded) {
$currentRepo = $repo;
break;
}
}
- // Return the specific Object responsible for this behavior
+ // Inject the full list ($this->repositories) into every page
+ // so they can render the navigation dropdown.
if (!$currentRepo) {
return new HomePage($this->repositories);
}
$git = new Git($currentRepo['path']);
if ($action === 'commits') {
- return new CommitsPage($currentRepo, $git, $hash);
+ return new CommitsPage($this->repositories, $currentRepo, $git, $hash);
}
- // Default to file browsing (Tree/Blob)
- return new FilePage($currentRepo, $git, $hash);
+ return new FilePage($this->repositories, $currentRepo, $git, $hash);
}
private function sanitizePath($path) {
$path = str_replace(['..', '\\', "\0"], ['', '/', ''], $path);
return preg_replace('/[^a-zA-Z0-9_\-\.\/]/', '', $path);
}
}
+
new/Views.php
<?php
-require_once 'Page.php';
-
abstract class BasePage implements Page {
+ protected $repositories;
protected $title;
- // Shared Layout Logic (Header/Nav)
- protected function renderLayout($contentCallback, $repo = null) {
+ public function __construct(array $repositories) {
+ $this->repositories = $repositories;
+ }
+
+ // Shared Layout Logic
+ protected function renderLayout($contentCallback, $currentRepo = null) {
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo Config::SITE_TITLE . ($this->title ? ' - ' . htmlspecialchars($this->title) : ''); ?></title>
<link rel="stylesheet" href="kimi-style.css">
<style>
- /* Inline styles preserved for portability */
.commit-list { margin-top: 20px; }
.commit-row { display: flex; padding: 10px 0; border-bottom: 1px solid #eee; gap: 15px; align-items: baseline; }
<nav class="nav">
<a href="?">Home</a>
- <?php if ($repo):
- $safeName = urlencode($repo['safe_name']); ?>
+ <?php if ($currentRepo):
+ $safeName = urlencode($currentRepo['safe_name']); ?>
<a href="?repo=<?php echo $safeName; ?>">Files</a>
<a href="?action=commits&repo=<?php echo $safeName; ?>">Commits</a>
<a href="?action=refs&repo=<?php echo $safeName; ?>">Branches</a>
+ <?php endif; ?>
+
+ <?php if ($currentRepo): ?>
+ <div class="repo-selector">
+ <label>Repository:</label>
+ <select onchange="window.location.href='?repo=' + encodeURIComponent(this.value)">
+ <option value="">Select repository...</option>
+ <?php foreach ($this->repositories as $r): ?>
+ <option value="<?php echo htmlspecialchars($r['safe_name']); ?>"
+ <?php echo $r['safe_name'] === $currentRepo['safe_name'] ? 'selected' : ''; ?>>
+ <?php echo htmlspecialchars($r['name']); ?>
+ </option>
+ <?php endforeach; ?>
+ </select>
+ </div>
<?php endif; ?>
</nav>
- <?php if ($repo): ?>
+
+ <?php if ($currentRepo): ?>
<div style="margin-top: 15px;">
- <span class="current-repo">Current: <strong><?php echo htmlspecialchars($repo['name']); ?></strong></span>
+ <span class="current-repo">Current: <strong><?php echo htmlspecialchars($currentRepo['name']); ?></strong></span>
</div>
<?php endif; ?>
class HomePage extends BasePage {
- private $repositories;
-
- public function __construct(array $repositories) {
- $this->repositories = $repositories;
- }
-
public function render() {
$this->renderLayout(function() {
class CommitsPage extends BasePage {
- private $repo;
+ private $currentRepo;
private $git;
private $hash;
- public function __construct($repo, $git, $hash) {
- $this->repo = $repo;
+ public function __construct($allRepos, $currentRepo, $git, $hash) {
+ parent::__construct($allRepos);
+ $this->currentRepo = $currentRepo;
$this->git = $git;
$this->hash = $hash;
- $this->title = $repo['name'];
+ $this->title = $currentRepo['name'];
}
$start = $this->hash ?: $main['hash'];
- $repoParam = '&repo=' . urlencode($this->repo['safe_name']);
+ $repoParam = '&repo=' . urlencode($this->currentRepo['safe_name']);
$this->git->history($start, 100, function($commit) use ($repoParam) {
});
echo '</div>';
- }, $this->repo);
+ }, $this->currentRepo);
}
private function renderBreadcrumbs() {
echo '<div class="breadcrumb">';
echo '<a href="?">Repositories</a><span>/</span>';
- echo '<a href="?repo=' . urlencode($this->repo['safe_name']) . '">' . htmlspecialchars($this->repo['name']) . '</a><span>/</span>';
+ echo '<a href="?repo=' . urlencode($this->currentRepo['safe_name']) . '">' . htmlspecialchars($this->currentRepo['name']) . '</a><span>/</span>';
echo '<span>Commits</span></div>';
}
}
class FilePage extends BasePage {
- private $repo;
+ private $currentRepo;
private $git;
private $hash;
- public function __construct($repo, $git, $hash) {
- $this->repo = $repo;
+ public function __construct($allRepos, $currentRepo, $git, $hash) {
+ parent::__construct($allRepos);
+ $this->currentRepo = $currentRepo;
$this->git = $git;
$this->hash = $hash;
- $this->title = $repo['name'];
+ $this->title = $currentRepo['name'];
}
$this->renderBlob($target);
}
- }, $this->repo);
+ }, $this->currentRepo);
}
private function renderTree($main, $targetHash, $entries) {
$this->renderBreadcrumbs($targetHash, 'Tree');
- echo '<h2>' . htmlspecialchars($this->repo['name']) . ' <span class="branch-badge">' . htmlspecialchars($main['name']) . '</span></h2>';
+ echo '<h2>' . htmlspecialchars($this->currentRepo['name']) . ' <span class="branch-badge">' . htmlspecialchars($main['name']) . '</span></h2>';
- // Sorting
usort($entries, function($a, $b) {
return ($b['isDir'] <=> $a['isDir']) ?: strcasecmp($a['name'], $b['name']);
});
echo '<div class="file-list">';
foreach ($entries as $e) {
$icon = $e['isDir'] ? '[dir]' : '[file]';
- $url = '?repo=' . urlencode($this->repo['safe_name']) . '&hash=' . $e['sha'];
+ $url = '?repo=' . urlencode($this->currentRepo['safe_name']) . '&hash=' . $e['sha'];
echo '<a href="' . $url . '" class="file-item">';
echo '<span class="file-mode">' . $e['mode'] . '</span>';
echo '<div class="breadcrumb">';
echo '<a href="?">Repositories</a><span>/</span>';
- echo '<a href="?repo=' . urlencode($this->repo['safe_name']) . '">' . htmlspecialchars($this->repo['name']) . '</a>';
+ echo '<a href="?repo=' . urlencode($this->currentRepo['safe_name']) . '">' . htmlspecialchars($this->currentRepo['name']) . '</a>';
if ($this->hash) echo '<span>/</span><span>' . $type . ' ' . substr($hash, 0, 7) . '</span>';
echo '</div>';
Delta 51 lines added, 40 lines removed, 11-line increase