239 lines
6.8 KiB
PHP
239 lines
6.8 KiB
PHP
<?php
|
|
// ─── SunScope — Tracking Stats ────────────────────────────────────────────────
|
|
|
|
$data_file = __DIR__ . '/data/tracking.json';
|
|
$tracking = [];
|
|
|
|
if (file_exists($data_file)) {
|
|
$tracking = json_decode(file_get_contents($data_file), true) ?? [];
|
|
}
|
|
|
|
// Sort days newest first
|
|
krsort($tracking);
|
|
|
|
// Collect all profile keys seen across all days, in preferred display order
|
|
$profile_order = ['basic','home','vehicle','farming','outdoors','alltemps','showall','custom'];
|
|
$all_profiles = [];
|
|
foreach ($tracking as $day => $data) {
|
|
foreach (array_keys($data['profiles'] ?? []) as $p) {
|
|
$all_profiles[$p] = true;
|
|
}
|
|
}
|
|
// Sort: preferred order first, then any extras alphabetically
|
|
$ordered = [];
|
|
foreach ($profile_order as $p) {
|
|
if (isset($all_profiles[$p])) $ordered[] = $p;
|
|
}
|
|
foreach (array_keys($all_profiles) as $p) {
|
|
if (!in_array($p, $ordered, true)) $ordered[] = $p;
|
|
}
|
|
|
|
$profile_labels = [
|
|
'basic' => 'Basic',
|
|
'home' => 'Home',
|
|
'vehicle' => 'Vehicle',
|
|
'farming' => 'Farming',
|
|
'outdoors' => 'Places',
|
|
'alltemps' => 'Temps',
|
|
'showall' => 'Show All',
|
|
'custom' => 'Custom',
|
|
];
|
|
|
|
$total_visits = array_sum(array_column($tracking, 'visits'));
|
|
$profile_totals = [];
|
|
foreach ($ordered as $p) {
|
|
$profile_totals[$p] = array_sum(array_map(fn($d) => $d['profiles'][$p] ?? 0, $tracking));
|
|
}
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>SunScope — Stats</title>
|
|
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>☀️</text></svg>" />
|
|
<link href="https://fonts.bunny.net/css2?family=Fraunces:ital,wght@0,900;1,300&family=Manrope:wght@400;600&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet" />
|
|
<style>
|
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
body {
|
|
font-family: Manrope, sans-serif;
|
|
background: #f5edd6;
|
|
color: #1e1208;
|
|
padding: 2rem;
|
|
min-height: 100vh;
|
|
}
|
|
.header {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 1rem;
|
|
margin-bottom: 2rem;
|
|
}
|
|
.logo {
|
|
font-family: Fraunces, serif;
|
|
font-size: 1.8rem;
|
|
line-height: 1;
|
|
letter-spacing: -0.02em;
|
|
}
|
|
.logo-sun { color: #c8922a; font-weight: 900; font-style: normal; }
|
|
.logo-scope { color: #1e1208; font-weight: 300; font-style: italic; }
|
|
.subtitle {
|
|
font-family: Fraunces, serif;
|
|
font-style: italic;
|
|
color: #7a5c2a;
|
|
font-size: 0.9rem;
|
|
}
|
|
.summary {
|
|
display: flex;
|
|
gap: 1.5rem;
|
|
flex-wrap: wrap;
|
|
margin-bottom: 2rem;
|
|
}
|
|
.pill {
|
|
background: #fffcf2;
|
|
border: 1.5px solid #c9b08a;
|
|
border-radius: 6px;
|
|
padding: 0.75rem 1.25rem;
|
|
}
|
|
.pill-label {
|
|
font-size: 0.7rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.08em;
|
|
color: #7a5c2a;
|
|
font-weight: 600;
|
|
}
|
|
.pill-value {
|
|
font-family: 'JetBrains Mono', monospace;
|
|
font-size: 1.5rem;
|
|
font-weight: 600;
|
|
color: #c8922a;
|
|
}
|
|
.table-wrap {
|
|
overflow-x: auto;
|
|
}
|
|
table {
|
|
border-collapse: collapse;
|
|
width: 100%;
|
|
min-width: 500px;
|
|
background: #fffcf2;
|
|
border: 1.5px solid #c9b08a;
|
|
border-radius: 6px;
|
|
overflow: hidden;
|
|
font-size: 0.875rem;
|
|
}
|
|
thead th {
|
|
background: #1e1208;
|
|
color: #f5edd6;
|
|
padding: 0.6rem 0.9rem;
|
|
text-align: left;
|
|
font-family: 'JetBrains Mono', monospace;
|
|
font-size: 0.72rem;
|
|
letter-spacing: 0.04em;
|
|
white-space: nowrap;
|
|
}
|
|
thead th.num { text-align: right; }
|
|
tbody tr:nth-child(even) { background: #fdf8ec; }
|
|
tbody tr:hover { background: #faefd8; }
|
|
td {
|
|
padding: 0.55rem 0.9rem;
|
|
border-top: 1px solid #e8dcc4;
|
|
font-family: 'JetBrains Mono', monospace;
|
|
font-size: 0.8rem;
|
|
white-space: nowrap;
|
|
}
|
|
td.num { text-align: right; }
|
|
td.zero { color: #c9b08a; }
|
|
tfoot td {
|
|
background: #f5edd6;
|
|
border-top: 2px solid #c9b08a;
|
|
font-weight: 600;
|
|
color: #7a5c2a;
|
|
}
|
|
.empty {
|
|
background: #fffcf2;
|
|
border: 1.5px solid #c9b08a;
|
|
border-radius: 6px;
|
|
padding: 2rem;
|
|
text-align: center;
|
|
color: #7a5c2a;
|
|
font-style: italic;
|
|
}
|
|
.back {
|
|
margin-top: 1.5rem;
|
|
font-size: 0.75rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
}
|
|
.back a { color: #b09870; text-decoration: none; }
|
|
.back a:hover { color: #c8922a; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="header">
|
|
<div class="logo">
|
|
<span class="logo-sun">SUN</span><span class="logo-scope">Scope</span>
|
|
</div>
|
|
<div class="subtitle">Usage stats</div>
|
|
</div>
|
|
|
|
<div class="summary">
|
|
<div class="pill">
|
|
<div class="pill-label">Total visits</div>
|
|
<div class="pill-value"><?= number_format($total_visits) ?></div>
|
|
</div>
|
|
<div class="pill">
|
|
<div class="pill-label">Days tracked</div>
|
|
<div class="pill-value"><?= count($tracking) ?></div>
|
|
</div>
|
|
<?php foreach ($ordered as $p): ?>
|
|
<div class="pill">
|
|
<div class="pill-label"><?= htmlspecialchars($profile_labels[$p] ?? $p) ?> clicks</div>
|
|
<div class="pill-value"><?= number_format($profile_totals[$p]) ?></div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
|
|
<?php if (empty($tracking)): ?>
|
|
<div class="empty">No tracking data yet.</div>
|
|
<?php else: ?>
|
|
<div class="table-wrap">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Date</th>
|
|
<th class="num">Visits</th>
|
|
<?php foreach ($ordered as $p): ?>
|
|
<th class="num"><?= htmlspecialchars($profile_labels[$p] ?? $p) ?></th>
|
|
<?php endforeach; ?>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($tracking as $day => $data): ?>
|
|
<tr>
|
|
<td><?= htmlspecialchars($day) ?></td>
|
|
<td class="num <?= $data['visits'] === 0 ? 'zero' : '' ?>"><?= $data['visits'] ?></td>
|
|
<?php foreach ($ordered as $p): $n = $data['profiles'][$p] ?? 0; ?>
|
|
<td class="num <?= $n === 0 ? 'zero' : '' ?>"><?= $n === 0 ? '—' : $n ?></td>
|
|
<?php endforeach; ?>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
<tfoot>
|
|
<tr>
|
|
<td>Total</td>
|
|
<td class="num"><?= number_format($total_visits) ?></td>
|
|
<?php foreach ($ordered as $p): ?>
|
|
<td class="num"><?= number_format($profile_totals[$p]) ?></td>
|
|
<?php endforeach; ?>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="back"><a href="/">← Back to SunScope</a></div>
|
|
|
|
</body>
|
|
</html>
|