Proje dosyaları eklendi

This commit is contained in:
2026-08-29 15:53:53 +03:00
commit d3313400ca
440 changed files with 24827 additions and 0 deletions
@@ -0,0 +1,92 @@
<style>
:root { --trafficpumper-admin-topbar-height: 4rem; }
.fi-body-has-topbar .fi-topbar { min-height: var(--trafficpumper-admin-topbar-height); padding-inline: 1rem; }
.fi-body-has-topbar .fi-topbar-start { width: calc(var(--sidebar-width) - 1rem); flex: 0 0 calc(var(--sidebar-width) - 1rem); margin-inline-end: 0; }
.fi-body-has-topbar .fi-topbar-start .fi-logo { height: 2.5rem; width: auto; max-width: min(15rem, 100%); margin-inline-start: 0; object-fit: contain; object-position: left center; }
.fi-body-has-topbar .fi-sidebar-header-ctn { display: none; }
.fi-body-has-topbar .fi-sidebar-nav { padding-top: 1.5rem; }
.fi-body-has-topbar .fi-topbar-end {
display: flex;
align-items: center;
flex-wrap: nowrap;
min-width: 0;
gap: .5rem;
margin-block: 0;
}
.trafficpumper-admin-preferences {
display: flex;
align-items: center;
flex: 0 0 auto;
flex-wrap: nowrap;
gap: .5rem;
margin-block: 0;
white-space: nowrap;
}
.tp-admin-control {
display: inline-flex;
align-items: center;
justify-content: center;
gap: .375rem;
height: 2.5rem;
min-width: 2.5rem;
padding-inline: .625rem;
border: 1px solid rgb(229 231 235);
border-radius: .625rem;
color: rgb(55 65 81);
background: transparent;
font-size: .75rem;
font-weight: 600;
line-height: 1;
}
.tp-admin-control:hover { background: rgb(249 250 251); color: rgb(17 24 39); }
.tp-admin-control:focus-visible { outline: 2px solid rgb(245 158 11); outline-offset: 2px; }
.dark .tp-admin-control { border-color: rgb(55 65 81); color: rgb(209 213 219); }
.dark .tp-admin-control:hover { background: rgb(31 41 55); color: rgb(255 255 255); }
.tp-admin-control .fi-icon { width: 1.125rem; height: 1.125rem; }
.tp-admin-control-chevron { width: .875rem !important; height: .875rem !important; }
.tp-admin-theme-icon { width: 1.125rem; font-size: 1rem; text-align: center; }
.tp-admin-user-control {
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
gap: .25rem;
height: 2.5rem;
margin: 0;
padding: .125rem .375rem .125rem .125rem;
border-radius: .625rem;
}
.tp-admin-user-control:hover { background: rgb(249 250 251); }
.dark .tp-admin-user-control:hover { background: rgb(31 41 55); }
.tp-admin-user-control:focus-visible { outline: 2px solid rgb(245 158 11); outline-offset: 2px; }
.tp-admin-avatar {
display: inline-flex;
align-items: center;
justify-content: center;
width: 2.25rem;
height: 2.25rem;
border-radius: 9999px;
background: rgb(245 158 11);
color: rgb(17 24 39);
font-size: .75rem;
font-weight: 700;
}
.tp-admin-user-chevron { width: .875rem; height: .875rem; color: rgb(107 114 128); }
.tp-admin-user-name, .tp-admin-user-email { display: block; max-width: 16rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tp-admin-user-email { margin-top: .125rem; color: rgb(107 114 128); font-size: .75rem; font-weight: 400; }
@media (max-width: 63.999rem) {
.fi-body-has-topbar .fi-topbar { gap: .5rem; }
.fi-body-has-topbar .fi-topbar-start { display: flex; width: auto; flex: 1 1 auto; margin: 0; min-width: 0; }
.fi-body-has-topbar .fi-topbar-start .fi-logo { height: 2.25rem; max-width: min(12rem, 42vw); }
.fi-body-has-topbar .fi-topbar-end { gap: .5rem; }
}
@media (max-width: 39.999rem) {
.fi-body-has-topbar .fi-topbar { padding-inline: .75rem; }
.fi-body-has-topbar .fi-topbar-start .fi-logo { height: 2rem; max-width: 32vw; }
.trafficpumper-admin-preferences, .fi-body-has-topbar .fi-topbar-end { gap: .25rem; }
.tp-admin-control { padding-inline: .5rem; }
.tp-admin-control-label, .tp-admin-control-chevron { display: none; }
.tp-admin-user-control { width: 2.5rem; padding: .125rem; }
.tp-admin-user-chevron { display: none; }
}
</style>
@@ -0,0 +1,20 @@
@php($activeLocale = app()->getLocale())
<x-filament::dropdown placement="bottom-end">
<x-slot name="trigger">
<button type="button" class="tp-admin-control" aria-label="{{ __('ui.language') }}" title="{{ __('ui.language') }}">
<x-filament::icon icon="heroicon-o-language" class="fi-icon fi-size-lg" />
<span class="tp-admin-control-label">{{ strtoupper($activeLocale) }}</span>
<x-filament::icon icon="heroicon-m-chevron-down" class="tp-admin-control-chevron" />
</button>
</x-slot>
<x-filament::dropdown.list>
@foreach(['tr' => 'Türkçe', 'en' => 'English'] as $code => $label)
<form method="POST" action="{{ route('locale.update') }}">@csrf
<input type="hidden" name="return_to" value="{{ request()->getRequestUri() }}">
<x-filament::dropdown.list.item type="submit" name="locale" :value="$code" :icon="$activeLocale === $code ? 'heroicon-o-check' : null">
{{ $label }}
</x-filament::dropdown.list.item>
</form>
@endforeach
</x-filament::dropdown.list>
</x-filament::dropdown>
@@ -0,0 +1,11 @@
<x-filament-panels::page>
<div class="grid gap-4 md:grid-cols-3">
<x-filament::section><x-slot name="heading">Aktivasyon</x-slot><p>{{ $summary['activation_mode'] }}</p><p>Kill switch: {{ $summary['kill_switch'] ? 'AKTİF' : 'Kapalı' }}</p><p>Circuit: {{ $summary['circuit_open'] ? 'Açık' : 'Kapalı' }}</p></x-filament::section>
<x-filament::section><x-slot name="heading">Son 24 saat</x-slot><p>Toplam: {{ $summary['checks_24h'] }}</p><p>Tamamlanan: {{ $summary['completed_24h'] }}</p><p>Başarısız: {{ $summary['failed_24h'] }}</p><p>Başarı: %{{ $summary['success_percent'] }}</p></x-filament::section>
<x-filament::section><x-slot name="heading">Kuyruk</x-slot><p>Provider bekleyen: {{ $summary['waiting_provider'] }}</p><p>Takılı: {{ $summary['stuck'] }}</p><p>Backlog: {{ $summary['queue_backlog'] }}</p><p>Failed jobs: {{ $summary['failed_jobs'] }}</p></x-filament::section>
<x-filament::section><x-slot name="heading">Bütçe (mikro USD)</x-slot><p>Günlük: {{ $summary['budget']['daily_micros'] }}</p><p>Aylık: {{ $summary['budget']['monthly_micros'] }}</p></x-filament::section>
<x-filament::section><x-slot name="heading">Ramp-up</x-slot><p>Başlangıç: {{ $summary['ramp_up']['started_at'] ?? 'Başlamadı' }}</p><p>Kullanım: {{ $summary['ramp_up']['used'] }}</p><p>Geçerli limit: {{ $summary['ramp_up']['limit'] ?? 'Sınırsız' }}</p></x-filament::section>
<x-filament::section><x-slot name="heading">Provider health</x-slot><p>Son kontrol: {{ $summary['last_health_at'] ?? 'Yapılmadı' }}</p><p>Credential: {{ config('serp.dataforseo.login') && config('serp.dataforseo.password') ? 'configured' : 'not configured' }}</p><p>Son hata: {{ $summary['last_error_category'] ?? '—' }}</p></x-filament::section>
</div>
@if(auth()->user()->hasRole('super_admin'))<div class="flex gap-3"><x-filament::button color="danger" wire:click="emergencyStop">Emergency stop</x-filament::button><x-filament::button color="gray" wire:click="clearEmergencyStop">Stop kaldır</x-filament::button></div>@endif
</x-filament-panels::page>
@@ -0,0 +1,7 @@
<div class="trafficpumper-admin-preferences" role="group" aria-label="{{ __('ui.preferences') }}">
@include('filament.locale-picker')
@include('filament.theme-picker')
@auth
@include('filament.user-menu')
@endauth
</div>
@@ -0,0 +1,9 @@
<script>{!! file_get_contents(resource_path('js/theme-manager.js')) !!}</script>
<script>
try { localStorage.setItem('theme', window.ThemeManager.getPreference()); } catch (error) {}
</script>
<script>
window.addEventListener('theme-changed', (event) => {
if (window.ThemeManager) window.ThemeManager.setPreference(event.detail);
});
</script>
@@ -0,0 +1,37 @@
<div
x-data="{
theme: localStorage.getItem('theme') || @js(filament()->getDefaultThemeMode()->value),
labels: @js(['light' => __('ui.light'), 'dark' => __('ui.dark'), 'system' => __('ui.system')]),
icons: { light: '☀', dark: '☾', system: '◐' },
choose(value) {
this.theme = value
window.dispatchEvent(new CustomEvent('theme-changed', { detail: value }))
},
}"
x-on:theme-changed.window="theme = $event.detail"
>
<x-filament::dropdown placement="bottom-end" teleport>
<x-slot name="trigger">
<button type="button" class="tp-admin-control" aria-label="{{ __('ui.theme') }}" title="{{ __('ui.theme') }}">
<span class="tp-admin-theme-icon" aria-hidden="true" x-text="icons[theme] || icons.system"></span>
<span class="tp-admin-control-label" x-text="labels[theme] || labels.system">{{ __('ui.system') }}</span>
<x-filament::icon icon="heroicon-m-chevron-down" class="tp-admin-control-chevron" />
</button>
</x-slot>
<x-filament::dropdown.list>
@foreach(['light' => ['heroicon-o-sun', __('ui.light')], 'dark' => ['heroicon-o-moon', __('ui.dark')], 'system' => ['heroicon-o-computer-desktop', __('ui.system')]] as $value => [$icon, $label])
<button
type="button"
class="fi-dropdown-list-item"
x-on:click="choose('{{ $value }}')"
x-bind:aria-current="theme === '{{ $value }}' ? 'true' : null"
>
<x-filament::icon :icon="$icon" class="fi-icon fi-size-md" />
<span class="fi-dropdown-list-item-label">{{ $label }}</span>
<span class="ms-auto" x-show="theme === '{{ $value }}'" aria-hidden="true"></span>
</button>
@endforeach
</x-filament::dropdown.list>
</x-filament::dropdown>
</div>
@@ -0,0 +1,37 @@
@php
$user = auth()->user();
$initials = collect(preg_split('/\s+/u', trim($user->name)) ?: [])
->filter()
->take(2)
->map(fn (string $part) => mb_strtoupper(mb_substr($part, 0, 1)))
->implode('');
$profileUrl = $user->can('update', $user)
? \App\Filament\Resources\Users\UserResource::getUrl('edit', ['record' => $user])
: \App\Filament\Resources\Users\UserResource::getUrl();
@endphp
<x-filament::dropdown placement="bottom-end" teleport>
<x-slot name="trigger">
<button type="button" class="tp-admin-user-control" aria-label="{{ __('filament-panels::layout.actions.open_user_menu.label') }}">
<span class="tp-admin-avatar" aria-hidden="true">{{ $initials }}</span>
<x-filament::icon icon="heroicon-m-chevron-down" class="tp-admin-user-chevron" />
</button>
</x-slot>
<x-filament::dropdown.header icon="heroicon-o-user-circle">
<span class="tp-admin-user-name">{{ $user->name }}</span>
<span class="tp-admin-user-email">{{ $user->email }}</span>
</x-filament::dropdown.header>
<x-filament::dropdown.list>
<x-filament::dropdown.list.item :href="$profileUrl" tag="a" icon="heroicon-o-user-circle">
{{ __('customer.profile') }}
</x-filament::dropdown.list.item>
<form method="POST" action="{{ filament()->getLogoutUrl() }}">
@csrf
<x-filament::dropdown.list.item type="submit" icon="heroicon-o-arrow-left-on-rectangle">
{{ __('ui.sign_out') }}
</x-filament::dropdown.list.item>
</form>
</x-filament::dropdown.list>
</x-filament::dropdown>