GitGram — header.php — GitGram
Hobbes_OS2_Archive / main / v1.07 / templates / header.php18,436 B↓ Raw
<?php
if (!defined('HOBBES')) { http_response_code(403); exit; }
$_settings = settings_load();
$_css      = $_settings['css'];
$_role     = effective_role();
$_user     = current_user();
// Apply user's personal theme if set, overriding the site default
if ($_user && !empty($_user['theme_preset']) && isset(THEME_PRESETS[$_user['theme_preset']])) {
    $_css = THEME_PRESETS[$_user['theme_preset']]['css'];
}
$_flashes  = get_flashes();
$_site     = h($_settings['site_name']);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><?php echo isset($page_title) ? h($page_title) . ' - ' . $_site : $_site; ?></title>
<script>(function(){var s=[13,15,17,20],i=+(localStorage.getItem('hfsz')||1);i=Math.max(0,Math.min(3,i));document.documentElement.style.fontSize=s[i]+'px';window.hFontScale=function(d){i=Math.max(0,Math.min(3,i+d));document.documentElement.style.fontSize=s[i]+'px';try{localStorage.setItem('hfsz',i);}catch(e){}};})();</script>
<style>
/* ── CSS Custom Properties ──────────────────── */
:root {
    --c-bg:        <?php echo h($_css['bg_color']); ?>;
    --c-text:      <?php echo h($_css['text_color']); ?>;
    --c-link:      <?php echo h($_css['link_color']); ?>;
    --c-visited:   <?php echo h($_css['visited_color']); ?>;
    --c-panel-bg:  <?php echo h($_css['panel_bg']); ?>;
    --c-btn-bg:    <?php echo h($_css['btn_bg']); ?>;
    --c-btn-text:  <?php echo h($_css['btn_text']); ?>;
    --c-border:    <?php echo h($_css['border_color']); ?>;
    --c-accent:    <?php echo h($_css['accent']); ?>;
    --c-th-bg:     <?php echo h($_css['th_bg']); ?>;
    --c-th-text:   <?php echo h($_css['th_text']); ?>;
    --c-tr-alt:    <?php echo h($_css['tr_alt_bg']); ?>;
    --c-tr-hover:  <?php echo h($_css['tr_hover_bg'] ?? $_css['tr_alt_bg']); ?>;
    --c-muted:     <?php echo h($_css['muted_color'] ?? '#666666'); ?>;
    --c-nav-bg:    <?php echo h($_css['nav_bg']); ?>;
    --c-nav-text:  <?php echo h($_css['nav_text']); ?>;
    --c-nav-hover: <?php echo h($_css['nav_hover_bg']); ?>;
    --c-hdr-bg:    <?php echo h($_css['header_bg']); ?>;
    --c-hdr-text:  <?php echo h($_css['header_text']); ?>;
    --c-input-bg:  <?php echo h($_css['input_bg']); ?>;
    --c-input-txt: <?php echo h($_css['input_text'] ?? $_css['text_color']); ?>;
    --c-input-bdr: <?php echo h($_css['input_border']); ?>;
    --c-err-bg:    <?php echo h($_css['error_bg']); ?>;
    --c-ok-bg:     <?php echo h($_css['success_bg']); ?>;
    --c-info-bg:   <?php echo h($_css['info_bg']); ?>;
}
/* ── Reset ─────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { font-size: 15px; }
body {
    font-family: 'Courier New', Courier, monospace;
    font-size: 1rem;
    background: var(--c-bg);
    color: var(--c-text);
    min-height: 100vh;
}

/* ── Links as buttons ───────────────────────── */
a {
    color: var(--c-btn-text);
    background: var(--c-btn-bg);
    border: 1px solid var(--c-border);
    padding: 0 4px;
    text-decoration: none;
}
a:visited { color: var(--c-visited); background: var(--c-btn-bg); }
a:hover {
    background: var(--c-btn-text);
    color: var(--c-btn-bg);
    text-decoration: none;
}

/* ── Layout ────────────────────────────────── */
#wrap { max-width: 1000px; margin: 0 auto; }

/* ── Header ────────────────────────────────── */
#site-header {
    background: var(--c-hdr-bg);
    color: var(--c-hdr-text);
    padding: 6px 10px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 3px ridge var(--c-border);
}
#site-header a {
    color: var(--c-hdr-text);
    background: transparent;
    border: none;
    padding: 0 4px;
    text-decoration: none;
}
#site-header a:visited { color: var(--c-hdr-text); background: transparent; }
#site-header a:hover { background: rgba(255,255,255,0.15); color: var(--c-hdr-text); }
#site-header h1 { font-size: 1.2rem; font-weight: bold; letter-spacing: 1px; }
#site-header .tagline { font-size: 0.75rem; opacity: 0.85; }
#user-bar { font-size: 0.75rem; text-align: right; }
#user-bar a { color: var(--c-hdr-text); margin-left: 8px; background: transparent; border: none; }
#user-bar a:hover { background: rgba(255,255,255,0.15); color: var(--c-hdr-text); }

/* ── Navigation ────────────────────────────── */
#nav {
    background: var(--c-nav-bg);
    padding: 0;
    border-bottom: 2px solid var(--c-border);
    display: flex;
    flex-wrap: wrap;
}
#nav a {
    color: var(--c-nav-text);
    background: transparent;
    border: none;
    border-right: 1px solid rgba(255,255,255,0.2);
    text-decoration: none;
    padding: 5px 12px;
    display: inline-block;
    font-weight: bold;
    font-size: 0.8rem;
}
#nav a:visited { color: var(--c-nav-text); background: transparent; }
#nav a:hover { background: var(--c-nav-hover); color: var(--c-nav-text); }
#nav a.active { background: var(--c-nav-hover); color: var(--c-nav-text); border-bottom: 2px solid #fff; }

/* ── Content ───────────────────────────────── */
#content { display: flex; gap: 0; }
#sidebar {
    width: 180px;
    min-width: 180px;
    background: var(--c-panel-bg);
    border-right: 1px solid var(--c-border);
    padding: 8px;
}
#main { flex: 1; padding: 10px; min-width: 0; }

/* ── Panels / boxes ────────────────────────── */
.panel {
    background: var(--c-panel-bg);
    border: 2px solid var(--c-border);
    margin-bottom: 10px;
}
.panel-title {
    background: var(--c-th-bg);
    color: var(--c-th-text);
    padding: 3px 8px;
    font-weight: bold;
    font-size: 0.8rem;
}
.panel-body { padding: 8px; }

/* ── Tables ────────────────────────────────── */
table.listing { width: 100%; border-collapse: collapse; font-size: 0.8rem; }
table.listing th {
    background: var(--c-th-bg);
    color: var(--c-th-text);
    padding: 3px 6px;
    text-align: left;
    border: 1px solid var(--c-border);
    white-space: nowrap;
}
table.listing td {
    padding: 2px 6px;
    border: 1px solid var(--c-border);
    vertical-align: top;
    color: var(--c-text);
    background: var(--c-bg);
}
table.listing tr:nth-child(even) td { background: var(--c-tr-alt); }
table.listing tr:hover td { background: var(--c-tr-hover); }
table.listing .icon { font-family: monospace; font-size: 0.75rem; white-space: nowrap; }
table.listing .size  { text-align: right; white-space: nowrap; }
table.listing .date  { white-space: nowrap; }

/* ── Forms ─────────────────────────────────── */
/* Global input theming — applies to all inputs, including sidebar search */
input, select, textarea {
    background: var(--c-input-bg);
    color: var(--c-input-txt);
    border: 1px solid var(--c-input-bdr);
}
form.std label { display: block; margin-top: 8px; font-weight: bold; font-size: 0.8rem; }
form.std input[type=text],
form.std input[type=password],
form.std input[type=email],
form.std input[type=url],
form.std input[type=number],
form.std select,
form.std textarea {
    width: 100%;
    background: var(--c-input-bg);
    color: var(--c-input-txt);
    border: 2px inset var(--c-input-bdr);
    padding: 3px 5px;
    font-family: inherit;
    font-size: 0.8rem;
    margin-top: 2px;
}
form.std textarea { height: 200px; resize: vertical; }
form.std .hint { font-size: 0.75rem; color: var(--c-muted); margin-top: 2px; }
form.std .row { margin-top: 12px; }

/* ── Buttons ───────────────────────────────── */
.btn {
    display: inline-block;
    background: var(--c-btn-bg);
    color: var(--c-btn-text);
    border: 2px outset var(--c-border);
    padding: 3px 12px;
    font-family: inherit;
    font-size: 0.8rem;
    cursor: pointer;
    text-decoration: none;
}
.btn:visited { background: var(--c-btn-bg); color: var(--c-btn-text); }
.btn:hover { border-style: inset; background: var(--c-btn-text); color: var(--c-btn-bg); }
.btn-primary {
    background: var(--c-th-bg);
    color: var(--c-th-text);
    border-color: var(--c-accent);
}
.btn-primary:visited { background: var(--c-th-bg); color: var(--c-th-text); }
.btn-primary:hover { background: var(--c-th-text); color: var(--c-th-bg); border-style: inset; }
.btn-danger  { background: #cc0000; color: #fff; border-color: #880000; }
.btn-danger:visited { background: #cc0000; color: #fff; }
.btn-danger:hover  { background: #fff; color: #cc0000; border-style: inset; }
.btn-small   { padding: 1px 6px; font-size: 0.75rem; }

/* ── Flash messages ────────────────────────── */
.flash { padding: 5px 10px; margin-bottom: 8px; border: 1px solid; font-size: 0.8rem; color: var(--c-text); }
.flash-error   { background: var(--c-err-bg);  border-color: #cc0000; }
.flash-success { background: var(--c-ok-bg);   border-color: #009900; }
.flash-info    { background: var(--c-info-bg); border-color: var(--c-accent); }

/* ── Category tree ─────────────────────────── */
.cat-tree, .cat-tree ul { list-style: none; padding-left: 10px; margin: 0; }
.cat-tree li { padding: 1px 0; }
.cat-tree li a {
    background: transparent;
    border: none;
    color: var(--c-link);
    font-size: 0.8rem;
    text-decoration: none;
    padding: 0;
}
.cat-tree li a:visited { background: transparent; color: var(--c-visited); }
.cat-tree li a:hover { background: transparent; color: var(--c-link); text-decoration: underline; }
.cat-tree li.active > a { font-weight: bold; }
.cat-tree > li { padding-left: 0; }
/* details/summary for collapsible subcategories */
.cat-tree details { display: block; }
.cat-tree summary.cat-summary {
    cursor: pointer;
    font-size: 0.8rem;
    list-style: none;
    padding: 0;
    display: block;
}
.cat-tree summary.cat-summary::-webkit-details-marker { display: none; }
.cat-tree summary.cat-summary::marker { display: none; }
.cat-tree summary.cat-summary::before {
    content: '[+] ';
    font-family: monospace;
    font-size: 0.65rem;
    color: var(--c-muted);
}
.cat-tree details[open] > summary.cat-summary::before { content: '[-] '; }

/* ── Pagination ────────────────────────────── */
.pagination { margin: 10px 0; }
.pagination a {
    display: inline-block;
    padding: 2px 6px;
    border: 1px solid var(--c-border);
    margin: 1px;
    text-decoration: none;
    background: var(--c-btn-bg);
    color: var(--c-btn-text);
}
.pagination a:visited { background: var(--c-btn-bg); color: var(--c-btn-text); }
.pagination a:hover { background: var(--c-btn-text); color: var(--c-btn-bg); }
.pagination a.current {
    background: var(--c-accent);
    color: var(--c-th-text);
    font-weight: bold;
    border-color: var(--c-accent);
}

/* ── Markdown content ──────────────────────── */
.md-content h1, .md-content h2, .md-content h3 {
    margin: 12px 0 6px;
    color: var(--c-accent);
}
.md-content p { margin: 6px 0; line-height: 1.5; }
.md-content ul, .md-content ol { margin: 6px 0 6px 20px; }
.md-content code { background: var(--c-tr-alt); color: var(--c-text); padding: 0 3px; font-size: 0.75rem; }
.md-content pre { background: var(--c-th-bg); color: var(--c-th-text); padding: 8px; overflow-x: auto; margin: 8px 0; }
.md-content blockquote { border-left: 3px solid var(--c-accent); padding-left: 8px; color: var(--c-muted); }
.md-content hr { border: 0; border-top: 1px solid var(--c-border); margin: 10px 0; }

/* ── Admin ─────────────────────────────────── */
.admin-grid { display: flex; flex-wrap: wrap; gap: 10px; }
.admin-card {
    background: var(--c-panel-bg);
    border: 2px solid var(--c-border);
    padding: 10px;
    width: 180px;
    text-align: center;
}
.admin-card a { font-weight: bold; }
.color-swatch { display: inline-block; width: 20px; height: 14px; border: 1px solid var(--c-border); vertical-align: middle; }

/* ── Misc ──────────────────────────────────── */
.info-box { border: 1px solid var(--c-border); background: var(--c-panel-bg); padding: 8px; margin: 8px 0; }
.tag { display: inline-block; background: var(--c-th-bg); color: var(--c-th-text); padding: 1px 5px; font-size: 0.75rem; margin: 1px; border: none; }
.tag:visited { background: var(--c-th-bg); color: var(--c-th-text); }
.tag:hover { background: var(--c-th-text); color: var(--c-th-bg); }
.role-badge { font-size: 0.65rem; font-weight: bold; padding: 1px 4px; border: 1px solid; }
.role-admin   { background: #400; color: #faa; border-color: #800; }
.role-editor  { background: #040; color: #afa; border-color: #080; }
.role-contributor { background: #004; color: #aaf; border-color: #008; }
.role-guest   { background: #444; color: #ddd; border-color: #666; }
/* Status indicator colors that adapt to theme */
.status-ok   { color: var(--c-accent); }
.status-warn { color: var(--c-link); }
.status-err  { color: #ff6666; }
hr { border: 0; border-top: 1px solid var(--c-border); margin: 8px 0; }
.right { float: right; }
.clear { clear: both; }
.muted { color: var(--c-muted); font-size: 0.75rem; }

<?php if (!empty($_settings['two_spot']['enabled'])):
    $_ts_bg   = h($_settings['two_spot']['bg']   ?? '#000080');
    $_ts_text = h($_settings['two_spot']['text'] ?? '#ffff00');
?>
/* ── IBM Two Spot ───────────────────────── */
:root { --ts-bg: <?php echo $_ts_bg; ?>; --ts-fg: <?php echo $_ts_text; ?>; }
*, *::before, *::after {
    background-color: var(--ts-bg) !important;
    color: var(--ts-fg) !important;
    border-color: var(--ts-fg) !important;
}
a, a:visited, .btn, .btn:visited, .btn-primary, .btn-danger {
    background-color: var(--ts-bg) !important;
    color: var(--ts-fg) !important;
    border-color: var(--ts-fg) !important;
}
a:hover, .btn:hover, .btn-primary:hover, .btn-danger:hover,
#nav a:hover, #nav a.active,
table.listing tr:hover td,
.cat-tree li a:hover,
.pagination a.current, .pagination a:hover {
    background-color: var(--ts-fg) !important;
    color: var(--ts-bg) !important;
}
<?php endif; ?>
</style>
</head>
<body>
<div id="wrap">
<div id="site-header">
  <div>
    <a href="/"><h1><?php echo $_site; ?></h1></a>
    <div class="tagline"><?php echo h($_settings['site_tagline']); ?></div>
  </div>
  <div id="user-bar">
<?php if ($_user): ?>
    Logged in as <strong><?php echo h($_user['username']); ?></strong>
    <span class="role-badge role-<?php echo h($_user['role']); ?>"><?php echo strtoupper(h($_user['role'])); ?></span>
    <a href="/profile">Profile</a>
    <?php if (can('invite')): ?><a href="/invite">Invites</a><?php endif; ?>
    <?php if (can('admin')): ?><a href="/admin">Admin</a><?php endif; ?>
    <a href="/logout">Logout</a>
<?php elseif ($_role === 'guest'): ?>
    <span class="role-badge role-guest">OS/2 GUEST</span>
    <a href="/login">Login</a>
<?php else: ?>
    <a href="/login">Login</a>
    <?php $s = settings_load(); if (!empty($s['open_registration'])): ?>
    <a href="/register">Register</a>
    <?php endif; ?>
<?php endif; ?>
  </div>
</div>
<div id="nav">
  <a href="/"<?php echo ($_page ?? '') === 'home' ? ' class="active"' : ''; ?>>Home</a>
<?php if (can('browse')): ?>
  <a href="/browse"<?php echo ($_page ?? '') === 'browse' ? ' class="active"' : ''; ?>>Browse</a>
  <a href="/search"<?php echo ($_page ?? '') === 'search' ? ' class="active"' : ''; ?>>Search</a>
<?php endif; ?>
<?php if (can('upload')): ?>
  <a href="/upload"<?php echo ($_page ?? '') === 'upload' ? ' class="active"' : ''; ?>>Upload</a>
<?php endif; ?>
<?php if (can('approve')): ?>
  <a href="/pool"<?php echo ($_page ?? '') === 'pool' ? ' class="active"' : ''; ?>>Pool</a>
<?php endif; ?>
<?php if (can('admin')): ?>
  <a href="/admin"<?php echo ($_page ?? '') === 'admin' ? ' class="active"' : ''; ?>>Admin</a>
<?php endif; ?>
  <span style="margin-left:auto;display:flex;align-items:center;">
    <a href="#" onclick="if(window.hFontScale)hFontScale(-1);return false;" style="padding:5px 8px;border-right:0;" title="Decrease font size">A-</a>
    <a href="#" onclick="if(window.hFontScale)hFontScale(1);return false;" style="padding:5px 8px;" title="Increase font size">A+</a>
  </span>
</div>
<?php if ($_flashes): ?>
<div id="flashes">
<?php foreach ($_flashes as $f): ?>
  <div class="flash flash-<?php echo h($f['type']); ?>"><?php echo h($f['msg']); ?></div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<div id="content">
<div id="sidebar">
<?php if (can('browse')): ?>
  <div class="panel">
    <div class="panel-title">Categories</div>
    <div class="panel-body">
<?php
$_cats = categories_load();
$_tree = build_category_tree($_cats);
echo render_category_tree($_tree, $active_category ?? '');
if (empty($_cats)) echo '<p class="muted">No categories yet.</p>';
?>
    </div>
  </div>
  <div class="panel">
    <div class="panel-title">Search</div>
    <div class="panel-body">
    <form method="get" action="/search">
      <input type="text" name="q" value="<?php echo h($_GET['q'] ?? ''); ?>" style="width:100%;">
      <button type="submit" class="btn" style="margin-top:4px;width:100%">Go</button>
    </form>
    </div>
  </div>
<?php else: ?>
  <div class="panel">
    <div class="panel-title">Access</div>
    <div class="panel-body">
      <p class="muted" style="line-height:1.5;">
        <a href="/login">Login</a> or
        <a href="/register/invite">use an invite</a>
        to browse the archive.
      </p>
    </div>
  </div>
<?php endif; ?>
</div>
<div id="main">
Ready
GitGram