| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- import Alpine from 'alpinejs';
- import 'htmx.org';
- import { Chart, BarController, BarElement, CategoryScale, LinearScale, Tooltip, Title } from 'chart.js';
- // Dark mode toggle. Layout's inline <head> script handles the FOUC-free
- // initial paint; this just wires the toggle button.
- function applyTheme(theme) {
- if (theme === 'dark') {
- document.documentElement.classList.add('dark');
- } else {
- document.documentElement.classList.remove('dark');
- }
- try {
- localStorage.setItem('irdb-theme', theme);
- } catch (e) {
- /* ignore */
- }
- }
- document.addEventListener('click', (e) => {
- const target = e.target.closest('[data-theme-toggle]');
- if (!target) return;
- const next = document.documentElement.classList.contains('dark') ? 'light' : 'dark';
- applyTheme(next);
- });
- // htmx: send the per-session CSRF token on every state-changing request.
- document.body.addEventListener('htmx:configRequest', (e) => {
- const meta = document.querySelector('meta[name="csrf-token"]');
- if (meta && meta.content) {
- e.detail.headers['X-CSRF-Token'] = meta.content;
- }
- });
- // Dashboard reports-per-hour chart. The canvas carries the buckets in a
- // `data-buckets` attribute (server-pre-bucketed; no AJAX). Chart.js is
- // tree-shaken to just the bar/linear pieces we need so the bundle stays
- // small.
- Chart.register(BarController, BarElement, CategoryScale, LinearScale, Tooltip, Title);
- function renderReportsChart() {
- const canvas = document.getElementById('reports-chart');
- if (!canvas) return;
- let buckets = [];
- try {
- buckets = JSON.parse(canvas.dataset.buckets || '[]');
- } catch (e) {
- return;
- }
- const labels = buckets.map((b) => (b.hour || '').replace(/.*T(\d{2}).*/, '$1h'));
- const data = buckets.map((b) => b.count || 0);
- const isDark = document.documentElement.classList.contains('dark');
- const tickColor = isDark ? '#94a3b8' : '#475569';
- const gridColor = isDark ? 'rgba(148,163,184,0.15)' : 'rgba(148,163,184,0.3)';
- new Chart(canvas, {
- type: 'bar',
- data: {
- labels,
- datasets: [{
- label: 'reports',
- data,
- backgroundColor: '#6366f1',
- }],
- },
- options: {
- responsive: true,
- maintainAspectRatio: false,
- plugins: { legend: { display: false } },
- scales: {
- x: { ticks: { color: tickColor }, grid: { color: gridColor } },
- y: { ticks: { color: tickColor, precision: 0 }, grid: { color: gridColor }, beginAtZero: true },
- },
- },
- });
- }
- document.addEventListener('DOMContentLoaded', renderReportsChart);
- window.Alpine = Alpine;
- Alpine.start();
|