Add a statistics page to the panel
The most read, reads per language with a daily chart, and published content nobody opened, each compared with the period before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
102
resources/views/filament/pages/statistics.blade.php
Normal file
102
resources/views/filament/pages/statistics.blade.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<x-filament-panels::page>
|
||||
<style>
|
||||
.st-periods { display: flex; gap: .5rem; flex-wrap: wrap; }
|
||||
.st-table { width: 100%; border-collapse: collapse; font-size: .875rem; }
|
||||
.st-table th { text-align: left; font-weight: 600; font-size: .75rem; text-transform: uppercase; opacity: .7; padding: .5rem; }
|
||||
.st-table td { padding: .5rem; border-top: 1px solid color-mix(in oklab, currentColor 10%, transparent); }
|
||||
.st-table td.num, .st-table th.num { text-align: right; font-variant-numeric: tabular-nums; }
|
||||
.st-up { color: #16a34a; } .st-down { color: #dc2626; }
|
||||
.st-locales { display: grid; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); gap: 1rem; }
|
||||
.st-locale strong { display: block; font-size: 1.5rem; font-variant-numeric: tabular-nums; }
|
||||
.st-bar { height: .375rem; border-radius: 999px; background: color-mix(in oklab, currentColor 10%, transparent); overflow: hidden; margin-top: .5rem; }
|
||||
.st-bar span { display: block; height: 100%; background: var(--primary-500, #f59e0b); }
|
||||
.st-unread { columns: 2 18rem; column-gap: 2rem; font-size: .875rem; }
|
||||
.st-unread li { break-inside: avoid; padding: .25rem 0; }
|
||||
</style>
|
||||
|
||||
@php($stats = $this->stats())
|
||||
|
||||
<div class="st-periods" role="group" aria-label="{{ __('panel.statistics.period') }}">
|
||||
@foreach (\App\Filament\Pages\Statistics::PERIODS as $period)
|
||||
<x-filament::button
|
||||
:color="$days === $period ? 'primary' : 'gray'"
|
||||
wire:click="$set('days', {{ $period }})"
|
||||
:aria-pressed="$days === $period ? 'true' : 'false'"
|
||||
>
|
||||
{{ __('panel.statistics.last_days', ['days' => $period]) }}
|
||||
</x-filament::button>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<x-filament::section :heading="__('panel.statistics.languages')" :description="__('panel.statistics.compared')">
|
||||
<div class="st-locales">
|
||||
@foreach ($stats->byLocale() as $locale => $row)
|
||||
@php($delta = $this->change($row['views'], $row['previous']))
|
||||
<div class="st-locale">
|
||||
<span>{{ config("locales.supported.{$locale}.native", $locale) }}</span>
|
||||
<strong>{{ number_format($row['views'], 0, ',', '.') }}</strong>
|
||||
<span @class(['st-up' => str_starts_with($delta, '+'), 'st-down' => str_starts_with($delta, '−')])>{{ $delta }}</span>
|
||||
· {{ $row['share'] }} %
|
||||
<div class="st-bar" aria-hidden="true"><span style="width: {{ $row['share'] }}%"></span></div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</x-filament::section>
|
||||
|
||||
@livewire(\App\Filament\Charts\ViewsByLanguageChart::class, ['days' => $days], key('views-chart-'.$days))
|
||||
|
||||
<x-filament::section :heading="__('panel.statistics.top')">
|
||||
@php($top = $stats->top())
|
||||
@if ($top->isEmpty())
|
||||
<p>{{ __('panel.statistics.no_views') }}</p>
|
||||
@else
|
||||
<table class="st-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{{ __('panel.statistics.columns.title') }}</th>
|
||||
<th scope="col">{{ __('panel.statistics.columns.type') }}</th>
|
||||
<th scope="col" class="num">{{ __('panel.statistics.columns.views') }}</th>
|
||||
<th scope="col" class="num">{{ __('panel.statistics.columns.change') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($top as $row)
|
||||
@php($delta = $this->change($row['views'], $row['previous']))
|
||||
<tr>
|
||||
<td>
|
||||
@if ($row['url'])
|
||||
<x-filament::link :href="$row['url']">{{ $row['title'] }}</x-filament::link>
|
||||
@else
|
||||
{{ $row['title'] }}
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ __('panel.statistics.types.'.$row['type']) }}</td>
|
||||
<td class="num">{{ number_format($row['views'], 0, ',', '.') }}</td>
|
||||
<td @class(['num', 'st-up' => str_starts_with($delta, '+'), 'st-down' => str_starts_with($delta, '−')])>{{ $delta }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@endif
|
||||
</x-filament::section>
|
||||
|
||||
<x-filament::section :heading="__('panel.statistics.unread')" :description="__('panel.statistics.unread_hint')" collapsible>
|
||||
@php($unread = $stats->unread())
|
||||
@if ($unread->isEmpty())
|
||||
<p>{{ __('panel.statistics.all_read') }}</p>
|
||||
@else
|
||||
<ul class="st-unread">
|
||||
@foreach ($unread as $row)
|
||||
<li>
|
||||
<x-filament::badge color="gray" size="sm" style="display: inline-flex">{{ __('panel.statistics.types.'.$row['type']) }}</x-filament::badge>
|
||||
@if ($row['url'])
|
||||
<x-filament::link :href="$row['url']">{{ $row['title'] }}</x-filament::link>
|
||||
@else
|
||||
{{ $row['title'] }}
|
||||
@endif
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
</x-filament::section>
|
||||
</x-filament-panels::page>
|
||||
Reference in New Issue
Block a user