Fixed log mobile view, plot, privacy banner
Build and Publish / Build and Publish Docker Image (push) Successful in 1m42s
Build and Publish / Build and Publish Docker Image (push) Successful in 1m42s
This commit is contained in:
+103
-44
@@ -25,7 +25,8 @@
|
||||
"visitor": "{{ t.analytics_log_visitor }}",
|
||||
"landing_view": "{{ t.analytics_ev_landing_view }}",
|
||||
"portal_open": "{{ t.analytics_ev_portal_open }}",
|
||||
"media_view": "{{ t.analytics_ev_media_view }}"
|
||||
"media_view": "{{ t.analytics_ev_media_view }}",
|
||||
"media_prefix": "{{ t.analytics_log_media_prefix }}"
|
||||
}'>
|
||||
<div class="analytics-presets">
|
||||
<button type="button" class="button is-small preset-btn" data-days="7">{{ t.analytics_preset_7 }}</button>
|
||||
@@ -52,14 +53,6 @@
|
||||
|
||||
<div class="analytics-kpis" id="anKpis"></div>
|
||||
|
||||
<div class="analytics-metric-toggles">
|
||||
<span class="toggles-label">{{ t.analytics_metrics_label }}:</span>
|
||||
<label><input type="checkbox" class="metric-toggle" data-key="landing_views"> {{ t.analytics_metric_landing_views }}</label>
|
||||
<label><input type="checkbox" class="metric-toggle" data-key="landing_unique" checked> {{ t.analytics_metric_landing_unique }}</label>
|
||||
<label><input type="checkbox" class="metric-toggle" data-key="portal_opens" checked> {{ t.analytics_metric_portal_opens }}</label>
|
||||
<label><input type="checkbox" class="metric-toggle" data-key="media_views" checked> {{ t.analytics_metric_media_views }}</label>
|
||||
</div>
|
||||
|
||||
<div class="analytics-chart-wrap">
|
||||
<div class="analytics-chart-box">
|
||||
<canvas id="anChart"></canvas>
|
||||
@@ -86,11 +79,19 @@
|
||||
<div class="analytics-log-card">
|
||||
<div class="analytics-log-head">
|
||||
<h2>{{ t.analytics_log_title }}</h2>
|
||||
<div class="analytics-metric-toggles analytics-log-filters">
|
||||
<span class="toggles-label">{{ t.analytics_log_show }}:</span>
|
||||
<label><input type="checkbox" class="log-type-toggle" data-type="landing_view"> {{ t.analytics_ev_landing_view }}</label>
|
||||
<label><input type="checkbox" class="log-type-toggle" data-type="portal_open" checked> {{ t.analytics_ev_portal_open }}</label>
|
||||
<label><input type="checkbox" class="log-type-toggle" data-type="media_view" checked> {{ t.analytics_ev_media_view }}</label>
|
||||
<div class="analytics-log-filters">
|
||||
<label class="log-chip" title="{{ t.analytics_ev_landing_view }}">
|
||||
<input type="checkbox" class="log-type-toggle" data-type="landing_view">
|
||||
<span>🌐 {{ t.analytics_ev_landing_short }}</span>
|
||||
</label>
|
||||
<label class="log-chip" title="{{ t.analytics_ev_portal_open }}">
|
||||
<input type="checkbox" class="log-type-toggle" data-type="portal_open" checked>
|
||||
<span>👤 {{ t.analytics_ev_portal_short }}</span>
|
||||
</label>
|
||||
<label class="log-chip" title="{{ t.analytics_ev_media_view }}">
|
||||
<input type="checkbox" class="log-type-toggle" data-type="media_view" checked>
|
||||
<span>🖼️ {{ t.analytics_ev_media_short }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="analytics-log" id="anLog"></div>
|
||||
@@ -127,7 +128,14 @@
|
||||
.analytics-log-card { background:#fff; border-radius:12px; padding:16px; box-shadow:0 1px 4px rgba(0,0,0,.06); margin-top:20px; }
|
||||
.analytics-log-card h2 { font-size:1rem; margin:0; }
|
||||
.analytics-log-head { display:flex; flex-wrap:wrap; gap:10px 18px; align-items:center; justify-content:space-between; margin-bottom:10px; }
|
||||
.analytics-log-filters { margin-bottom:0; }
|
||||
.analytics-log-filters { display:flex; flex-wrap:wrap; gap:6px; }
|
||||
.log-chip { display:inline-flex; align-items:center; gap:5px; padding:4px 11px; border-radius:999px; border:1px solid var(--admin-border,#e0e0e6); background:#f5f5f7; color:#8a8a95; font-size:.8rem; line-height:1.3; cursor:pointer; user-select:none; white-space:nowrap; transition:background .12s,color .12s,border-color .12s; }
|
||||
.log-chip input { position:absolute; opacity:0; width:0; height:0; pointer-events:none; }
|
||||
.log-chip:has(input:checked) { background:var(--admin-accent-soft,#eef0fb); border-color:#c9c6ee; color:#5b4fc4; font-weight:600; }
|
||||
@media (max-width:600px) {
|
||||
.analytics-log-head { gap:8px; margin-bottom:8px; }
|
||||
.log-chip { padding:5px 12px; font-size:.82rem; }
|
||||
}
|
||||
.analytics-log { height:460px; overflow-y:auto; overflow-x:hidden; border:1px solid #f0f0f0; border-radius:8px; }
|
||||
.an-log-row { display:grid; grid-template-columns:40px 1fr; gap:10px; align-items:start; padding:11px 12px; border-bottom:1px solid #f2f2f4; font-size:.85rem; }
|
||||
.an-log-row:last-child { border-bottom:none; }
|
||||
@@ -136,7 +144,10 @@
|
||||
.an-log-main { min-width:0; }
|
||||
.an-log-head { display:flex; flex-wrap:wrap; gap:2px 8px; align-items:baseline; }
|
||||
.an-log-event { font-weight:650; }
|
||||
.an-log-client { color:#7c6ed4; font-weight:600; }
|
||||
.an-log-client { color:#7c6ed4; font-weight:600; text-decoration:none; }
|
||||
.an-log-client:hover { text-decoration:underline; }
|
||||
.an-log-num { color:#7c6ed4; font-weight:600; text-decoration:none; }
|
||||
a.an-log-num:hover { text-decoration:underline; }
|
||||
.an-log-time { color:#9a9aa6; font-size:.75rem; white-space:nowrap; margin-left:auto; }
|
||||
.an-log-meta { color:#8a8a95; font-size:.76rem; margin-top:4px; display:flex; flex-direction:column; gap:2px; }
|
||||
.an-log-meta .an-log-line { display:flex; flex-wrap:wrap; gap:4px 12px; }
|
||||
@@ -157,7 +168,7 @@
|
||||
var L = JSON.parse(controls.getAttribute('data-labels'));
|
||||
|
||||
var META = [
|
||||
{ key: 'landing_views', color: '#7c6ed4' },
|
||||
{ key: 'landing_views', color: '#7c6ed4', hidden: true },
|
||||
{ key: 'landing_unique', color: '#00b496' },
|
||||
{ key: 'portal_opens', color: '#ff8c26' },
|
||||
{ key: 'media_views', color: '#ff5287' }
|
||||
@@ -212,6 +223,23 @@
|
||||
|
||||
function metricLabel(key) { return L[key] || key; }
|
||||
|
||||
var MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
||||
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||
|
||||
// Turns an ISO bucket label into a short display date:
|
||||
// "2026-04-11" -> "11 Apr", "2026-04" -> "Apr 2026".
|
||||
function formatLabel(raw) {
|
||||
if (!raw) { return raw; }
|
||||
var parts = String(raw).split('-');
|
||||
if (parts.length === 3) {
|
||||
return parseInt(parts[2], 10) + ' ' + MONTHS[parseInt(parts[1], 10) - 1];
|
||||
}
|
||||
if (parts.length === 2) {
|
||||
return MONTHS[parseInt(parts[1], 10) - 1] + ' ' + parts[0];
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
function hexToRgba(hex, a) {
|
||||
var n = parseInt(hex.slice(1), 16);
|
||||
return 'rgba(' + ((n >> 16) & 255) + ',' + ((n >> 8) & 255) + ',' + (n & 255) + ',' + a + ')';
|
||||
@@ -239,10 +267,6 @@
|
||||
|
||||
function initChart() {
|
||||
var ctx = document.getElementById('anChart').getContext('2d');
|
||||
var enabled = {};
|
||||
document.querySelectorAll('.metric-toggle').forEach(function (cb) {
|
||||
enabled[cb.getAttribute('data-key')] = cb.checked;
|
||||
});
|
||||
var datasets = META.map(function (m) {
|
||||
return {
|
||||
label: metricLabel(m.key),
|
||||
@@ -253,7 +277,7 @@
|
||||
pointRadius: 2,
|
||||
tension: 0.25,
|
||||
fill: true,
|
||||
hidden: enabled[m.key] === false,
|
||||
hidden: !!m.hidden,
|
||||
_key: m.key
|
||||
};
|
||||
});
|
||||
@@ -265,8 +289,39 @@
|
||||
maintainAspectRatio: false,
|
||||
animation: false,
|
||||
interaction: { mode: 'index', intersect: false },
|
||||
plugins: { legend: { display: false } },
|
||||
scales: { y: { beginAtZero: true, ticks: { precision: 0 } } }
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'top',
|
||||
labels: {
|
||||
usePointStyle: true,
|
||||
pointStyle: 'rectRounded',
|
||||
boxWidth: 12,
|
||||
boxHeight: 12,
|
||||
padding: 12,
|
||||
font: { size: 12 }
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: function (items) {
|
||||
return items.length ? formatLabel(items[0].label) : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
ticks: {
|
||||
autoSkip: true,
|
||||
maxRotation: 0,
|
||||
callback: function (value) {
|
||||
return formatLabel(this.getLabelForValue(value));
|
||||
}
|
||||
}
|
||||
},
|
||||
y: { beginAtZero: true, ticks: { precision: 0 } }
|
||||
}
|
||||
},
|
||||
plugins: [messageOverlay]
|
||||
});
|
||||
@@ -401,15 +456,6 @@
|
||||
fromInput.addEventListener('change', load);
|
||||
toInput.addEventListener('change', load);
|
||||
granSelect.addEventListener('change', load);
|
||||
document.querySelectorAll('.metric-toggle').forEach(function (cb) {
|
||||
cb.addEventListener('change', function () {
|
||||
if (!chart) { return; }
|
||||
chart.data.datasets.forEach(function (ds) {
|
||||
if (ds._key === cb.getAttribute('data-key')) { ds.hidden = !cb.checked; }
|
||||
});
|
||||
chart.update();
|
||||
});
|
||||
});
|
||||
|
||||
// --- Event log (newest first, infinite scroll of older events) ---------
|
||||
var logEl = document.getElementById('anLog');
|
||||
@@ -487,16 +533,37 @@
|
||||
|
||||
var head = document.createElement('div');
|
||||
head.className = 'an-log-head';
|
||||
|
||||
var ev = document.createElement('span');
|
||||
ev.className = 'an-log-event';
|
||||
ev.textContent = L[e.event_type] || e.event_type;
|
||||
head.appendChild(ev);
|
||||
if (e.event_type === 'media_view') {
|
||||
ev.textContent = L.media_prefix;
|
||||
head.appendChild(ev);
|
||||
if (e.media && e.media.media_id != null) {
|
||||
var num = document.createElement(e.client_id != null ? 'a' : 'span');
|
||||
num.className = 'an-log-num';
|
||||
num.textContent = '№' + e.media.media_id;
|
||||
if (e.client_id != null) { num.href = '/admin/media?client_id=' + e.client_id; }
|
||||
head.appendChild(num);
|
||||
}
|
||||
} else {
|
||||
ev.textContent = L[e.event_type] || e.event_type;
|
||||
head.appendChild(ev);
|
||||
}
|
||||
|
||||
if (e.client_name) {
|
||||
var cl = document.createElement('span');
|
||||
var cl;
|
||||
if (e.client_id != null) {
|
||||
cl = document.createElement('a');
|
||||
cl.href = '/admin/clients/' + e.client_id + '/edit';
|
||||
} else {
|
||||
cl = document.createElement('span');
|
||||
}
|
||||
cl.className = 'an-log-client';
|
||||
cl.textContent = e.client_name;
|
||||
head.appendChild(cl);
|
||||
}
|
||||
|
||||
var tm = document.createElement('span');
|
||||
tm.className = 'an-log-time';
|
||||
tm.textContent = e.created_at;
|
||||
@@ -512,14 +579,6 @@
|
||||
if (ua) { line1.appendChild(metaSpan(ua)); }
|
||||
if (line1.childNodes.length) { meta.appendChild(line1); }
|
||||
|
||||
if (e.path && e.path !== '/') {
|
||||
var line2 = metaLine();
|
||||
var code = document.createElement('code');
|
||||
code.textContent = e.path;
|
||||
line2.appendChild(code);
|
||||
meta.appendChild(line2);
|
||||
}
|
||||
|
||||
if (e.referer) {
|
||||
var line3 = metaLine();
|
||||
var ref = document.createElement('span');
|
||||
|
||||
Reference in New Issue
Block a user