PriviMetrics
Version 1.0.9 • 43 files • 278.98 KB
Files
.last_check
admin.php
assets/.htaccess
assets/dashboard-chart.php
assets/dashboard-logic.php
assets/dashboard-modals.php
assets/dashboard-tables.php
assets/dashboard-template.php
assets/trends-template.php
chosen-limits.php
dashboard.php
data/.htaccess
extensions-load.php
extensions.php
extensions.xml
extensions/.htaccess
extensions/extensions_off.txt
functions.php
getCountryFrom/db-ip.php
getCountryFrom/geo-lite.php
getCountryFrom/ip-api-com.php
getCountryFrom/ip-info.php
getCountryFrom/ip-stack.php
getCountryFrom/ip2location-io.php
getCountryFrom/privacy-friendly.php
index.html
install.php
limits-options.php
new_version.php
privimetrics-div.js
privimetrics.php
public.php
scripts.js
settings-config.php
settings.php
signup.php
storage.php
styles-mobile.css
styles.css
trends.css
trends.php
updater/index.php
version.txt
assets/trends-template.php
<?php
// ===============================================================================
// PriviMetrics - Trends Template
// ===============================================================================
?>
<!DOCTYPE html>
<html lang="en" data-theme="<?= $theme ?>" data-font="<?= htmlspecialchars($settings['ui_font'] ?? 'sora') ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Weekly Trends - <?= sanitize($config['site_name']) ?></title>
<link rel="stylesheet" media="screen and (max-width: 900px)" href="styles-mobile.css?v=<?= time(); ?>">
<link rel="stylesheet" media="screen and (min-width: 901px)" href="styles.css?v=<?= time(); ?>">
<link rel="stylesheet" href="trends.css?v=<?= time(); ?>">
<link rel="preload" href="fonts/sora.ttf" as="font" type="font/ttf" crossorigin>
<style>
.trends-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24px;
padding: 16px;
background: var(--card-bg);
border-radius: 12px;
}
.week-navigation {
display: flex;
align-items: center;
gap: 12px;
}
.week-info {
text-align: center;
padding: 0 24px;
}
.week-info h2 {
margin: 0 0 4px 0;
font-size: 1.5em;
color: var(--text-primary);
}
.week-info .date-range {
font-size: 0.9em;
color: var(--text-secondary);
}
.comparison-selector {
display: flex;
gap: 8px;
padding: 12px;
background: var(--bg-secondary);
border-radius: 8px;
margin-bottom: 16px;
}
.comparison-selector button {
padding: 8px 16px;
border: 1px solid var(--border-color);
background: var(--card-bg);
border-radius: 6px;
cursor: pointer;
transition: all 0.2s;
}
.comparison-selector button.active {
background: var(--primary-color);
color: white;
border-color: var(--primary-color);
}
.trend-indicator {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 4px 8px;
border-radius: 4px;
font-size: 0.85em;
font-weight: 600;
}
.trend-up {
background: rgba(34, 197, 94, 0.1);
color: #22c55e;
}
.trend-down {
background: rgba(239, 68, 68, 0.1);
color: #ef4444;
}
.trend-neutral {
background: rgba(156, 163, 175, 0.1);
color: #9ca3af;
}
.daily-chart {
margin: 24px 0;
padding: 20px;
background: var(--card-bg);
border-radius: 12px;
}
.daily-bars {
display: flex;
gap: 8px;
align-items: flex-end;
height: 200px;
margin-top: 16px;
}
.day-bar {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.bar-container {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
flex: 1;
}
.bar {
width: 100%;
background: linear-gradient(180deg, var(--primary-color), var(--primary-color-dark));
border-radius: 6px 6px 0 0;
transition: all 0.3s;
cursor: pointer;
position: relative;
}
.bar:hover {
opacity: 0.8;
}
.bar-value {
position: absolute;
top: -24px;
left: 50%;
transform: translateX(-50%);
font-size: 0.75em;
font-weight: 600;
color: var(--text-primary);
white-space: nowrap;
}
.day-label {
font-size: 0.85em;
color: var(--text-secondary);
font-weight: 500;
}
.comparison-table {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
margin-top: 24px;
}
@media (max-width: 768px) {
.trends-header {
flex-direction: column;
gap: 16px;
}
.week-navigation {
width: 100%;
justify-content: space-between;
}
.comparison-table {
grid-template-columns: 1fr;
}
.daily-bars {
height: 150px;
}
}
</style>
</head>
<body>
<div class="header">
<div class="logo">
<div class="logo-icon">
<?php
$logo = $config['site_logo'];
if (str_starts_with($logo, 'img:')) {
$logoFile = substr($logo, 4);
echo '<img src="' . htmlspecialchars($logoFile) . '" alt="' . htmlspecialchars($config['site_name']) . '" style="height:40px;">';
} else {
echo '<span>' . htmlspecialchars($logo) . '</span>';
}
?>
</div>
<div class="logo-text"><?= sanitize($config['site_name']) ?></div>
<div class="logo-text"><span style="font-weight: 300;">| Trends</span></div>
</div>
<div class="header-actions">
<a href="dashboard.php<?= $_SERVER['QUERY_STRING'] ? '?' . $_SERVER['QUERY_STRING'] : '' ?>" class="btn btn-secondary">←</a>
<a href="?site=<?= $selectedSiteId ?>&week=<?= $selectedWeek ?>&theme=<?= $theme === 'dark' ? 'light' : 'dark' ?>&compare=<?= $compareMode ?>" class="btn btn-secondary">
<?= $theme === 'dark' ? '<svg class="icon" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"> <circle cx="12" cy="12" r="5" /> <path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" /></svg>' : '<svg class="icon" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"> <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" /></svg>' ?>
</a>
<a href="settings.php" class="btn btn-secondary">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path>
<circle cx="12" cy="12" r="3"></circle>
</svg>
Settings
</a>
<a href="admin.php?logout=1" class="btn btn-secondary">Logout</a>
</div>
</div>
<div class="container">
<?php if ($currentSite): ?>
<!-- Site Selector -->
<div class="toolbar" style="margin-bottom: 16px;">
<select onchange="window.location.href='?site=' + this.value + '&week=<?= $selectedWeek ?>&theme=<?= $theme ?>&compare=<?= $compareMode ?>'">
<?php foreach ($sites->site as $site): ?>
<option value="<?= (string)$site->id ?>" <?=(string)$site->id === $selectedSiteId ? 'selected' : '' ?>>
<?= sanitize((string)$site->name) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<?php if (!empty($availableWeeks)): ?>
<!-- Week Navigation -->
<div class="trends-header">
<div class="week-navigation">
<?php
$currentIndex = array_search($selectedWeek, array_column($availableWeeks, 'id'));
$hasPrev = $currentIndex !== false && $currentIndex < count($availableWeeks) - 1;
$hasNext = $currentIndex !== false && $currentIndex > 0;
$prevWeek = $hasPrev ? $availableWeeks[$currentIndex + 1]['id'] : '';
$nextWeek = $hasNext ? $availableWeeks[$currentIndex - 1]['id'] : '';
?>
<button class="btn btn-secondary"
<?= !$hasPrev ? 'disabled' : '' ?>
onclick="window.location.href='?site=<?= $selectedSiteId ?>&week=<?= $prevWeek ?>&theme=<?= $theme ?>&compare=<?= $compareMode ?>'">
← Previous
</button>
<select class="btn" style="min-width: 200px;"
onchange="window.location.href='?site=<?= $selectedSiteId ?>&week=' + this.value + '&theme=<?= $theme ?>&compare=<?= $compareMode ?>'">
<?php foreach ($availableWeeks as $week): ?>
<option value="<?= $week['id'] ?>" <?= $week['id'] === $selectedWeek ? 'selected' : '' ?>>
<?= htmlspecialchars($week['label'] . ' - ' . $week['date_range']) ?>
</option>
<?php endforeach; ?>
</select>
<button class="btn btn-secondary"
<?= !$hasNext ? 'disabled' : '' ?>
onclick="window.location.href='?site=<?= $selectedSiteId ?>&week=<?= $nextWeek ?>&theme=<?= $theme ?>&compare=<?= $compareMode ?>'">
Next →
</button>
</div>
</div>
<?php if ($currentWeekInfo): ?>
<div class="week-info" style="text-align: center; margin-bottom: 24px;">
<h2>Week <?= $currentWeekInfo['week'] ?>, <?= $currentWeekInfo['year'] ?></h2>
<div class="date-range">
<?= date('F d', $currentWeekInfo['start']) ?> - <?= date('F d, Y', $currentWeekInfo['end']) ?>
</div>
</div>
<!-- Comparison Mode -->
<div class="comparison-selector">
<span style="align-self: center; margin-right: 8px; color: var(--text-secondary);">Compare with:</span>
<button class="<?= $compareMode === 'none' ? 'active' : '' ?>"
onclick="window.location.href='?site=<?= $selectedSiteId ?>&week=<?= $selectedWeek ?>&theme=<?= $theme ?>&compare=none'">
No Comparison
</button>
<button class="<?= $compareMode === 'previous' ? 'active' : '' ?>"
onclick="window.location.href='?site=<?= $selectedSiteId ?>&week=<?= $selectedWeek ?>&theme=<?= $theme ?>&compare=previous'">
Previous Week
</button>
<button class="<?= $compareMode === 'year' ? 'active' : '' ?>"
onclick="window.location.href='?site=<?= $selectedSiteId ?>&week=<?= $selectedWeek ?>&theme=<?= $theme ?>&compare=year'">
Same Week Last Year
</button>
</div>
<?php if ($weekStats && $weekStats['total_visits'] > 0): ?>
<!-- Main Stats -->
<div class="stats-grid">
<div class="stat-card">
<div class="stat-label">Total Visits</div>
<div class="stat-value">
<?= formatNumber($weekStats['total_visits']) ?>
<?php if ($changes && isset($changes['visits'])): ?>
<span class="trend-indicator trend-<?= $changes['visits'] > 0 ? 'up' : ($changes['visits'] < 0 ? 'down' : 'neutral') ?>">
<?= $changes['visits'] > 0 ? '↑' : ($changes['visits'] < 0 ? '↓' : '→') ?>
<?= abs($changes['visits']) ?>%
</span>
<?php endif; ?>
</div>
</div>
<div class="stat-card">
<div class="stat-label">Pages Visited</div>
<div class="stat-value"><?= count($weekStats['pages']) ?></div>
</div>
<div class="stat-card">
<div class="stat-label">Top Country</div>
<div class="stat-value">
<?php if (!empty($weekStats['countries'])): ?>
<?= htmlspecialchars(array_key_first($weekStats['countries'])) ?>
<?php else: ?>
-
<?php endif; ?>
</div>
</div>
<div class="stat-card">
<div class="stat-label">Searches</div>
<div class="stat-value"><?= count($weekStats['searches']) ?></div>
</div>
</div>
<!-- Daily Breakdown Chart -->
<div class="daily-chart">
<h3 style="margin: 0 0 16px 0;">Daily Breakdown</h3>
<div class="daily-bars">
<?php
$maxVisits = max(array_column($weekStats['daily_breakdown'], 'visits'));
$dayOrder = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
foreach ($dayOrder as $day):
$dayData = $weekStats['daily_breakdown'][$day] ?? ['visits' => 0];
$height = $maxVisits > 0 ? ($dayData['visits'] / $maxVisits) * 100 : 0;
?>
<div class="day-bar">
<div class="bar-container">
<?php if ($dayData['visits'] > 0): ?>
<div class="bar" style="height: <?= $height ?>%;" title="<?= $dayData['visits'] ?> visits">
<div class="bar-value"><?= $dayData['visits'] ?></div>
</div>
<?php endif; ?>
</div>
<div class="day-label"><?= $day ?></div>
</div>
<?php endforeach; ?>
</div>
</div>
<!-- Top Lists -->
<div class="comparison-table">
<!-- Top Pages -->
<div class="table-card">
<h3>Top Pages</h3>
<table>
<thead>
<tr>
<th>Page</th>
<th style="text-align: right;">Visits</th>
</tr>
</thead>
<tbody>
<?php
$topPages = array_slice($weekStats['pages'], 0, 10, true);
foreach ($topPages as $page => $count):
?>
<tr>
<td><?= htmlspecialchars($page) ?></td>
<td style="text-align: right;"><?= formatNumber($count) ?></td>
</tr>
<?php endforeach; ?>
<?php if (empty($topPages)): ?>
<tr><td colspan="2" style="text-align: center; color: var(--text-tertiary);">No data</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
<!-- Top Countries -->
<div class="table-card">
<h3>Top Countries</h3>
<table>
<thead>
<tr>
<th>Country</th>
<th style="text-align: right;">Visits</th>
</tr>
</thead>
<tbody>
<?php
$topCountries = array_slice($weekStats['countries'], 0, 10, true);
foreach ($topCountries as $country => $count):
?>
<tr>
<td><?= htmlspecialchars($country) ?></td>
<td style="text-align: right;"><?= formatNumber($count) ?></td>
</tr>
<?php endforeach; ?>
<?php if (empty($topCountries)): ?>
<tr><td colspan="2" style="text-align: center; color: var(--text-tertiary);">No data</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<?php else: ?>
<div class="no-data">
<h3>No data for this week</h3>
<p>No visits were recorded during this week.</p>
</div>
<?php endif; ?>
<?php endif; ?>
<?php else: ?>
<div class="no-data">
<h3>No data available</h3>
<p>Start tracking to see weekly trends.</p>
<a href="index.php" class="btn btn-primary" style="margin-top: 16px;">Go to Dashboard</a>
</div>
<?php endif; ?>
<?php else: ?>
<div class="no-data">
<h3>No sites configured</h3>
<p>Add your first site to start tracking.</p>
<a href="index.php" class="btn btn-primary" style="margin-top: 16px;">Go to Dashboard</a>
</div>
<?php endif; ?>
</div>
<script src="scripts.js?v=<?= time(); ?>"></script>
</body>
</html>