Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/treetrek.git
BasePage.php
+<?php
+require_once 'File.php';
+require_once 'FileRenderer.php';
+
+abstract class BasePage implements Page {
+ protected $repositories;
+ protected $title;
+
+ public function __construct(array $repositories) {
+ $this->repositories = $repositories;
+ }
+
+ 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="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
+ <link rel="stylesheet" href="repo.css">
+ </head>
+ <body>
+ <div class="container">
+ <header>
+ <h1><?php echo Config::SITE_TITLE; ?></h1>
+ <nav class="nav">
+ <a href="?">Home</a>
+ <?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 ($currentRepo): ?>
+ <div style="margin-top: 15px;">
+ <span class="current-repo">Current: <strong><?php echo htmlspecialchars($currentRepo['name']); ?></strong></span>
+ </div>
+ <?php endif; ?>
+ </header>
+
+ <?php call_user_func($contentCallback); ?>
+
+ </div>
+ </body>
+ </html>
+ <?php
+ }
+}
CommitsPage.php
+<?php
+class CommitsPage extends BasePage {
+ private $currentRepo;
+ private $git;
+ private $hash;
+
+ public function __construct($allRepos, $currentRepo, $git, $hash) {
+ parent::__construct($allRepos);
+ $this->currentRepo = $currentRepo;
+ $this->git = $git;
+ $this->hash = $hash;
+ $this->title = $currentRepo['name'];
+ }
+
+ public function render() {
+ $this->renderLayout(function() {
+ $main = $this->git->getMainBranch();
+ if (!$main) {
+ echo '<div class="empty-state"><h3>No branches</h3><p>Empty repository.</p></div>';
+ return;
+ }
+
+ $this->renderBreadcrumbs();
+ echo '<h2>Commit History <span class="branch-badge">' . htmlspecialchars($main['name']) . '</span></h2>';
+ echo '<div class="commit-list">';
+
+ $start = $this->hash ?: $main['hash'];
+ $repoParam = '&repo=' . urlencode($this->currentRepo['safe_name']);
+
+ $this->git->history($start, 100, function($commit) use ($repoParam) {
+ $msg = htmlspecialchars(explode("\n", $commit->message)[0]);
+ echo '<div class="commit-row">';
+ echo '<a href="?action=commit&hash=' . $commit->sha . $repoParam . '" class="sha">' . substr($commit->sha, 0, 7) . '</a>';
+ echo '<span class="message">' . $msg . '</span>';
+ echo '<span class="meta">' . htmlspecialchars($commit->author) . ' &bull; ' . date('Y-m-d', $commit->date) . '</span>';
+ echo '</div>';
+ });
+ echo '</div>';
+ }, $this->currentRepo);
+ }
+
+ private function renderBreadcrumbs() {
+ echo '<div class="breadcrumb">';
+ echo '<a href="?">Repositories</a><span>/</span>';
+ echo '<a href="?repo=' . urlencode($this->currentRepo['safe_name']) . '">' . htmlspecialchars($this->currentRepo['name']) . '</a><span>/</span>';
+ echo '<span>Commits</span></div>';
+ }
+}
FilePage.php
+<?php
+
+class FilePage extends BasePage {
+ private $currentRepo;
+ private $git;
+ private $hash;
+
+ public function __construct($allRepos, $currentRepo, $git, $hash) {
+ parent::__construct($allRepos);
+ $this->currentRepo = $currentRepo;
+ $this->git = $git;
+ $this->hash = $hash;
+ $this->title = $currentRepo['name'];
+ }
+
+ public function render() {
+ $this->renderLayout(function() {
+ $main = $this->git->getMainBranch();
+ if (!$main) {
+ echo '<div class="empty-state"><h3>No branches</h3></div>';
+ return;
+ }
+
+ $target = $this->hash ?: $main['hash'];
+ $entries = [];
+
+ // Entries are now File objects
+ $this->git->walk($target, function($file) use (&$entries) {
+ $entries[] = $file;
+ });
+
+ if (!empty($entries)) {
+ $this->renderTree($main, $target, $entries);
+ } else {
+ $this->renderBlob($target);
+ }
+ }, $this->currentRepo);
+ }
+
+ private function renderTree($main, $targetHash, $entries) {
+ $this->renderBreadcrumbs($targetHash, 'Tree');
+ echo '<h2>' . htmlspecialchars($this->currentRepo['name']) . ' <span class="branch-badge">' . htmlspecialchars($main['name']) . '</span></h2>';
+
+ // Encapsulated sorting via File::compare
+ usort($entries, function($a, $b) {
+ return $a->compare($b);
+ });
+
+ echo '<div class="file-list">';
+ $renderer = new HtmlFileRenderer($this->currentRepo['safe_name']);
+
+ foreach ($entries as $file) {
+ $file->render($renderer);
+ }
+
+ echo '</div>';
+ }
+
+ private function renderBlob($targetHash) {
+ $repoParam = '&repo=' . urlencode($this->currentRepo['safe_name']);
+
+ $size = $this->git->getObjectSize($targetHash);
+
+ $buffer = '';
+ $this->git->stream($targetHash, function($d) use (&$buffer) {
+ if (strlen($buffer) < 12) $buffer .= $d;
+ });
+
+ $filename = $_GET['name'] ?? '';
+ $category = MediaTypeSniffer::isCategory($buffer, $filename);
+ $mimeType = MediaTypeSniffer::isMediaType($buffer, $filename);
+
+ $this->renderBreadcrumbs($targetHash, 'File');
+
+ // UPDATED: Handle empty files
+ if ($size === 0) {
+ $this->renderDownloadState($targetHash, "This file is empty.");
+ return;
+ }
+
+ $rawUrl = '?action=raw&hash=' . $targetHash . $repoParam . '&name=' . urlencode($filename);
+
+ if ($category === MediaTypeSniffer::CAT_VIDEO) {
+ echo '<div class="blob-content" style="text-align:center; padding: 20px; background: #000;">';
+ echo '<video controls style="max-width: 100%; max-height: 80vh;">';
+ echo '<source src="' . $rawUrl . '" type="' . $mimeType . '">';
+ echo 'Your browser does not support the video element.';
+ echo '</video>';
+ echo '</div>';
+
+ } elseif ($category === MediaTypeSniffer::CAT_AUDIO) {
+ echo '<div class="blob-content" style="text-align:center; padding: 40px; background: #f6f8fa;">';
+ echo '<audio controls style="width: 100%; max-width: 600px;">';
+ echo '<source src="' . $rawUrl . '" type="' . $mimeType . '">';
+ echo 'Your browser does not support the audio element.';
+ echo '</audio>';
+ echo '</div>';
+
+ } elseif ($category === MediaTypeSniffer::CAT_IMAGE) {
+ echo '<div class="blob-content" style="text-align:center; padding: 20px; background: #f6f8fa;">';
+ echo '<img src="' . $rawUrl . '" style="max-width: 100%; border: 1px solid #dfe2e5;">';
+ echo '</div>';
+
+ } elseif ($category === MediaTypeSniffer::CAT_TEXT) {
+ if ($size > 524288) {
+ $this->renderDownloadState($targetHash, "File is too large to display (" . $this->formatSize($size) . ").");
+ } else {
+ $content = '';
+ $this->git->stream($targetHash, function($d) use (&$content) { $content .= $d; });
+ echo '<div class="blob-content"><pre class="blob-code">' . htmlspecialchars($content) . '</pre></div>';
+ }
+
+ } else {
+ $this->renderDownloadState($targetHash, "This is a binary file.");
+ }
+ }
+
+ private function renderDownloadState($hash, $reason) {
+ $url = '?action=raw&hash=' . $hash . '&repo=' . urlencode($this->currentRepo['safe_name']);
+ echo '<div class="empty-state" style="text-align: center; padding: 40px; border: 1px solid #e1e4e8; border-radius: 6px; margin-top: 10px;">';
+ echo '<p style="margin-bottom: 20px; color: #586069;">' . htmlspecialchars($reason) . '</p>';
+ echo '<a href="' . $url . '" style="display: inline-block; padding: 6px 16px; background: #0366d6; color: white; text-decoration: none; border-radius: 6px; font-weight: 600;">Download Raw File</a>';
+ echo '</div>';
+ }
+
+ private function formatSize($size) {
+ if ($size <= 0) return '0 B';
+ $units = ['B', 'KB', 'MB', 'GB'];
+ $i = (int)floor(log($size, 1024));
+ return round($size / pow(1024, $i), 1) . ' ' . $units[$i];
+ }
+
+ private function renderBreadcrumbs($hash, $type) {
+ echo '<div class="breadcrumb">';
+ echo '<a href="?">Repositories</a><span>/</span>';
+ 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>';
+ }
+}
HomePage.php
+<?php
+class HomePage extends BasePage {
+ public function render() {
+ $this->renderLayout(function() {
+ echo '<h2>Repositories</h2>';
+ if (empty($this->repositories)) {
+ echo '<div class="empty-state">No repositories found in ' . htmlspecialchars(Config::getReposPath()) . '</div>';
+ return;
+ }
+ echo '<div class="repo-grid">';
+ foreach ($this->repositories as $repo) {
+ $this->renderRepoCard($repo);
+ }
+ echo '</div>';
+ });
+ }
+
+ private function renderRepoCard($repo) {
+ $git = new Git($repo['path']);
+ $main = $git->getMainBranch();
+
+ $stats = ['branches' => 0, 'tags' => 0];
+ $git->eachBranch(function() use (&$stats) { $stats['branches']++; });
+ $git->eachTag(function() use (&$stats) { $stats['tags']++; });
+
+ echo '<a href="?repo=' . urlencode($repo['safe_name']) . '" class="repo-card">';
+ echo '<h3>' . htmlspecialchars($repo['name']) . '</h3>';
+ if ($main) echo '<p>Branch: ' . htmlspecialchars($main['name']) . '</p>';
+ echo '<p>' . $stats['branches'] . ' branches, ' . $stats['tags'] . ' tags</p>';
+
+ if ($main) {
+ $git->history('HEAD', 1, function($c) use ($repo) {
+ $renderer = new HtmlFileRenderer($repo['safe_name']);
+ echo '<p style="margin-top: 8px; color: #58a6ff;">';
+ $renderer->renderTime($c->date);
+ echo '</p>';
+ });
+ }
+ echo '</a>';
+ }
+}
RawPage.php
+<?php
+
+class RawPage implements Page {
+ private $git;
+ private $hash;
+
+ public function __construct($git, $hash) {
+ $this->git = $git;
+ $this->hash = $hash;
+ }
+
+ public function render() {
+ while (ob_get_level()) ob_end_clean();
+
+ $size = $this->git->getObjectSize($this->hash);
+ $filename = $_GET['name'] ?? 'file';
+
+ $buffer = '';
+ $this->git->stream($this->hash, function($d) use (&$buffer) {
+ if (strlen($buffer) < 12) $buffer .= $d;
+ });
+
+ $mime = MediaTypeSniffer::isMediaType($buffer, $filename);
+ if (!$mime) $mime = 'application/octet-stream';
+
+ header('Content-Type: ' . $mime);
+ header('Content-Length: ' . $size);
+ header('Content-Disposition: inline; filename="' . basename($filename) . '"');
+
+ $this->git->stream($this->hash, function($data) {
+ echo $data;
+ });
+
+ exit;
+ }
+}
Views.php
require_once 'FileRenderer.php';
-abstract class BasePage implements Page {
- protected $repositories;
- protected $title;
-
- public function __construct(array $repositories) {
- $this->repositories = $repositories;
- }
-
- 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="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
- <link rel="stylesheet" href="repo.css">
- </head>
- <body>
- <div class="container">
- <header>
- <h1><?php echo Config::SITE_TITLE; ?></h1>
- <nav class="nav">
- <a href="?">Home</a>
- <?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 ($currentRepo): ?>
- <div style="margin-top: 15px;">
- <span class="current-repo">Current: <strong><?php echo htmlspecialchars($currentRepo['name']); ?></strong></span>
- </div>
- <?php endif; ?>
- </header>
-
- <?php call_user_func($contentCallback); ?>
-
- </div>
- </body>
- </html>
- <?php
- }
-}
-
-class HomePage extends BasePage {
- public function render() {
- $this->renderLayout(function() {
- echo '<h2>Repositories</h2>';
- if (empty($this->repositories)) {
- echo '<div class="empty-state">No repositories found in ' . htmlspecialchars(Config::getReposPath()) . '</div>';
- return;
- }
- echo '<div class="repo-grid">';
- foreach ($this->repositories as $repo) {
- $this->renderRepoCard($repo);
- }
- echo '</div>';
- });
- }
-
- private function renderRepoCard($repo) {
- $git = new Git($repo['path']);
- $main = $git->getMainBranch();
-
- $stats = ['branches' => 0, 'tags' => 0];
- $git->eachBranch(function() use (&$stats) { $stats['branches']++; });
- $git->eachTag(function() use (&$stats) { $stats['tags']++; });
-
- echo '<a href="?repo=' . urlencode($repo['safe_name']) . '" class="repo-card">';
- echo '<h3>' . htmlspecialchars($repo['name']) . '</h3>';
- if ($main) echo '<p>Branch: ' . htmlspecialchars($main['name']) . '</p>';
- echo '<p>' . $stats['branches'] . ' branches, ' . $stats['tags'] . ' tags</p>';
-
- if ($main) {
- $git->history('HEAD', 1, function($c) use ($repo) {
- $renderer = new HtmlFileRenderer($repo['safe_name']);
- echo '<p style="margin-top: 8px; color: #58a6ff;">';
- $renderer->renderTime($c->date);
- echo '</p>';
- });
- }
- echo '</a>';
- }
-}
-
-class CommitsPage extends BasePage {
- private $currentRepo;
- private $git;
- private $hash;
-
- public function __construct($allRepos, $currentRepo, $git, $hash) {
- parent::__construct($allRepos);
- $this->currentRepo = $currentRepo;
- $this->git = $git;
- $this->hash = $hash;
- $this->title = $currentRepo['name'];
- }
-
- public function render() {
- $this->renderLayout(function() {
- $main = $this->git->getMainBranch();
- if (!$main) {
- echo '<div class="empty-state"><h3>No branches</h3><p>Empty repository.</p></div>';
- return;
- }
-
- $this->renderBreadcrumbs();
- echo '<h2>Commit History <span class="branch-badge">' . htmlspecialchars($main['name']) . '</span></h2>';
- echo '<div class="commit-list">';
-
- $start = $this->hash ?: $main['hash'];
- $repoParam = '&repo=' . urlencode($this->currentRepo['safe_name']);
-
- $this->git->history($start, 100, function($commit) use ($repoParam) {
- $msg = htmlspecialchars(explode("\n", $commit->message)[0]);
- echo '<div class="commit-row">';
- echo '<a href="?action=commit&hash=' . $commit->sha . $repoParam . '" class="sha">' . substr($commit->sha, 0, 7) . '</a>';
- echo '<span class="message">' . $msg . '</span>';
- echo '<span class="meta">' . htmlspecialchars($commit->author) . ' &bull; ' . date('Y-m-d', $commit->date) . '</span>';
- echo '</div>';
- });
- echo '</div>';
- }, $this->currentRepo);
- }
-
- private function renderBreadcrumbs() {
- echo '<div class="breadcrumb">';
- echo '<a href="?">Repositories</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 $currentRepo;
- private $git;
- private $hash;
-
- public function __construct($allRepos, $currentRepo, $git, $hash) {
- parent::__construct($allRepos);
- $this->currentRepo = $currentRepo;
- $this->git = $git;
- $this->hash = $hash;
- $this->title = $currentRepo['name'];
- }
-
- public function render() {
- $this->renderLayout(function() {
- $main = $this->git->getMainBranch();
- if (!$main) {
- echo '<div class="empty-state"><h3>No branches</h3></div>';
- return;
- }
-
- $target = $this->hash ?: $main['hash'];
- $entries = [];
-
- // Entries are now File objects
- $this->git->walk($target, function($file) use (&$entries) {
- $entries[] = $file;
- });
-
- if (!empty($entries)) {
- $this->renderTree($main, $target, $entries);
- } else {
- $this->renderBlob($target);
- }
- }, $this->currentRepo);
- }
-
- private function renderTree($main, $targetHash, $entries) {
- $this->renderBreadcrumbs($targetHash, 'Tree');
- echo '<h2>' . htmlspecialchars($this->currentRepo['name']) . ' <span class="branch-badge">' . htmlspecialchars($main['name']) . '</span></h2>';
-
- // Encapsulated sorting via File::compare
- usort($entries, function($a, $b) {
- return $a->compare($b);
- });
-
- echo '<div class="file-list">';
- $renderer = new HtmlFileRenderer($this->currentRepo['safe_name']);
-
- foreach ($entries as $file) {
- $file->render($renderer);
- }
-
- echo '</div>';
- }
-
- private function renderBlob($targetHash) {
- $repoParam = '&repo=' . urlencode($this->currentRepo['safe_name']);
-
- $size = $this->git->getObjectSize($targetHash);
-
- $buffer = '';
- $this->git->stream($targetHash, function($d) use (&$buffer) {
- if (strlen($buffer) < 12) $buffer .= $d;
- });
-
- $filename = $_GET['name'] ?? '';
- $category = MediaTypeSniffer::isCategory($buffer, $filename);
- $mimeType = MediaTypeSniffer::isMediaType($buffer, $filename);
-
- $this->renderBreadcrumbs($targetHash, 'File');
-
- // UPDATED: Handle empty files
- if ($size === 0) {
- $this->renderDownloadState($targetHash, "This file is empty.");
- return;
- }
-
- $rawUrl = '?action=raw&hash=' . $targetHash . $repoParam . '&name=' . urlencode($filename);
-
- if ($category === MediaTypeSniffer::CAT_VIDEO) {
- echo '<div class="blob-content" style="text-align:center; padding: 20px; background: #000;">';
- echo '<video controls style="max-width: 100%; max-height: 80vh;">';
- echo '<source src="' . $rawUrl . '" type="' . $mimeType . '">';
- echo 'Your browser does not support the video element.';
- echo '</video>';
- echo '</div>';
-
- } elseif ($category === MediaTypeSniffer::CAT_AUDIO) {
- echo '<div class="blob-content" style="text-align:center; padding: 40px; background: #f6f8fa;">';
- echo '<audio controls style="width: 100%; max-width: 600px;">';
- echo '<source src="' . $rawUrl . '" type="' . $mimeType . '">';
- echo 'Your browser does not support the audio element.';
- echo '</audio>';
- echo '</div>';
-
- } elseif ($category === MediaTypeSniffer::CAT_IMAGE) {
- echo '<div class="blob-content" style="text-align:center; padding: 20px; background: #f6f8fa;">';
- echo '<img src="' . $rawUrl . '" style="max-width: 100%; border: 1px solid #dfe2e5;">';
- echo '</div>';
-
- } elseif ($category === MediaTypeSniffer::CAT_TEXT) {
- if ($size > 524288) {
- $this->renderDownloadState($targetHash, "File is too large to display (" . $this->formatSize($size) . ").");
- } else {
- $content = '';
- $this->git->stream($targetHash, function($d) use (&$content) { $content .= $d; });
- echo '<div class="blob-content"><pre class="blob-code">' . htmlspecialchars($content) . '</pre></div>';
- }
-
- } else {
- $this->renderDownloadState($targetHash, "This is a binary file.");
- }
- }
-
- private function renderDownloadState($hash, $reason) {
- $url = '?action=raw&hash=' . $hash . '&repo=' . urlencode($this->currentRepo['safe_name']);
- echo '<div class="empty-state" style="text-align: center; padding: 40px; border: 1px solid #e1e4e8; border-radius: 6px; margin-top: 10px;">';
- echo '<p style="margin-bottom: 20px; color: #586069;">' . htmlspecialchars($reason) . '</p>';
- echo '<a href="' . $url . '" style="display: inline-block; padding: 6px 16px; background: #0366d6; color: white; text-decoration: none; border-radius: 6px; font-weight: 600;">Download Raw File</a>';
- echo '</div>';
- }
-
- private function formatSize($size) {
- if ($size <= 0) return '0 B';
- $units = ['B', 'KB', 'MB', 'GB'];
- $i = (int)floor(log($size, 1024));
- return round($size / pow(1024, $i), 1) . ' ' . $units[$i];
- }
-
- private function renderBreadcrumbs($hash, $type) {
- echo '<div class="breadcrumb">';
- echo '<a href="?">Repositories</a><span>/</span>';
- 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>';
- }
-}
-
-class RawPage implements Page {
- private $git;
- private $hash;
-
- public function __construct($git, $hash) {
- $this->git = $git;
- $this->hash = $hash;
- }
-
- public function render() {
- while (ob_get_level()) ob_end_clean();
-
- $size = $this->git->getObjectSize($this->hash);
- $filename = $_GET['name'] ?? 'file';
-
- $buffer = '';
- $this->git->stream($this->hash, function($d) use (&$buffer) {
- if (strlen($buffer) < 12) $buffer .= $d;
- });
-
- $mime = MediaTypeSniffer::isMediaType($buffer, $filename);
- if (!$mime) $mime = 'application/octet-stream';
-
- header('Content-Type: ' . $mime);
- header('Content-Length: ' . $size);
- header('Content-Disposition: inline; filename="' . basename($filename) . '"');
-
- $this->git->stream($this->hash, function($data) {
- echo $data;
- });
-
- exit;
- }
-}
-
+require_once 'BasePage.php';
+require_once 'HomePage.php';
+require_once 'CommitsPage.php';
+require_once 'FilePage.php';
+require_once 'RawPage.php';

Splits views into separate files

Author Dave Jarvis <email>
Date 2026-02-08 23:48:57 GMT-0800
Commit 43c6f066c73de4f6ccf5a00f96c210b0c58a9690
Parent 8f1ed88
Delta 337 lines added, 327 lines removed, 10-line increase