Files
animexe/resources/views/admin/trending/index.blade.php
T
2026-07-14 00:01:48 +03:00

275 lines
12 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@extends('admin.layouts.app')
@section('title','Trend Yönetimi')
@section('page-title','Trend Yönetimi')
@push('styles')
<style>
.trend-item {
display:flex; align-items:center; gap:12px;
padding:12px 16px;
border-bottom:1px solid var(--border);
transition:background .12s;
}
.trend-item:last-child { border-bottom:none; }
.trend-item:hover { background:rgba(255,255,255,0.02); }
.trend-rank {
width:28px; height:28px;
border-radius:8px;
background:var(--surface);
display:flex; align-items:center; justify-content:center;
font-size:12px; font-weight:800; color:var(--text2);
flex-shrink:0;
}
.trend-cover {
width:36px; height:52px;
object-fit:cover; border-radius:6px;
flex-shrink:0;
}
.trend-cover-ph {
width:36px; height:52px;
background:var(--surface);
border-radius:6px; flex-shrink:0;
display:flex; align-items:center; justify-content:center;
color:var(--text3); font-size:14px;
}
.search-result-item {
display:flex; align-items:center; gap:10px;
padding:10px 12px; border-radius:8px;
margin-bottom:4px;
background:rgba(255,255,255,0.03);
border:1px solid var(--border);
}
</style>
@endpush
@section('content')
<div class="page-header">
<div>
<h5 style="font-size:18px;font-weight:700;color:var(--text);margin:0">Trend Yönetimi</h5>
<div style="font-size:13px;color:var(--text2);margin-top:2px">
Ana sayfada gösterilecek trend animeleri yönet
@if($lastComputed)
<span class="badge bg-secondary ms-2">Son hesap: {{ $lastComputed }}</span>
@else
<span class="badge bg-danger ms-2">Skor henüz hesaplanmadı</span>
@endif
</div>
</div>
<div class="d-flex gap-2">
<button class="btn btn-warning" id="btn-compute-scores" onclick="computeScores()">
<i class="bi bi-lightning-fill me-1"></i>
Trend Skorlarını Hesapla
</button>
</div>
</div>
<div id="compute-result" style="display:none" class="alert alert-success mb-3"></div>
<div class="row g-4">
{{-- ── Sol: Manuel Trend ── --}}
<div class="col-lg-6">
<div class="card h-100">
<div class="card-header">
<i class="bi bi-fire" style="color:var(--warning)"></i>
<h6>Manuel Trend Listesi</h6>
<span style="font-size:12px;color:var(--text2)">{{ $manual->count() }} anime</span>
</div>
<div class="card-body p-0">
@if($manual->isEmpty())
<div class="empty-state">
<i class="bi bi-fire"></i>
<h6>Manuel trend seçilmedi</h6>
<p>Sağdan anime ekleyin veya otomatik trend kullanılır.</p>
</div>
@else
@foreach($manual as $anime)
<div class="trend-item">
<div class="trend-rank">{{ $anime->trending_order }}</div>
@if($anime->coverUrl)
<img src="{{ $anime->coverUrl }}" class="trend-cover" alt="">
@else
<div class="trend-cover-ph"><i class="bi bi-image"></i></div>
@endif
<div style="flex:1;min-width:0">
<div style="font-size:13.5px;font-weight:700;color:var(--text)" class="text-truncate">{{ $anime->title }}</div>
<div style="font-size:12px;color:var(--text2)">{{ $anime->release_year }} · {{ strtoupper($anime->type) }}</div>
</div>
<div class="d-flex gap-1">
@if(!$loop->first)
<form method="POST" action="{{ route('admin.trending.move',$anime) }}">
@csrf
<input type="hidden" name="direction" value="up">
<button type="submit" class="btn btn-sm btn-secondary" title="Yukarı">
<i class="bi bi-chevron-up"></i>
</button>
</form>
@endif
@if(!$loop->last)
<form method="POST" action="{{ route('admin.trending.move',$anime) }}">
@csrf
<input type="hidden" name="direction" value="down">
<button type="submit" class="btn btn-sm btn-secondary" title="Aşağı">
<i class="bi bi-chevron-down"></i>
</button>
</form>
@endif
<form method="POST" action="{{ route('admin.trending.toggle',$anime) }}">
@csrf
<button type="submit" class="btn btn-sm btn-outline-danger" title="Çıkar">
<i class="bi bi-x-lg"></i>
</button>
</form>
</div>
</div>
@endforeach
@endif
</div>
</div>
</div>
{{-- ── Sağ: Otomatik + Ekle ── --}}
<div class="col-lg-6">
{{-- Arama ve Ekle --}}
<div class="card mb-3">
<div class="card-header">
<i class="bi bi-search" style="color:var(--info)"></i>
<h6>Anime Ekle</h6>
</div>
<div class="card-body">
<div class="search-input-wrap mb-2">
<i class="bi bi-search"></i>
<input type="text" id="trending-search" class="form-control"
placeholder="Anime adı yazın..." autocomplete="off">
</div>
<div id="search-results" style="display:none"></div>
</div>
</div>
{{-- Otomatik Trend --}}
<div class="card mb-3">
<div class="card-header">
<i class="bi bi-graph-up-arrow" style="color:var(--info)"></i>
<h6>Otomatik Trend</h6>
<span style="font-size:12px;color:var(--text2)">YouTube-benzeri trending skoru</span>
</div>
<div class="card-body p-0">
@foreach($autoTrending as $anime)
<div class="trend-item">
@if($anime->coverUrl)
<img src="{{ $anime->coverUrl }}" class="trend-cover" alt="">
@else
<div class="trend-cover-ph"><i class="bi bi-image"></i></div>
@endif
<div style="flex:1;min-width:0">
<div style="font-size:13px;font-weight:700;color:var(--text)" class="text-truncate">{{ $anime->title }}</div>
<div style="font-size:12px;color:var(--text2)">
@if($anime->trending_score > 0)
<i class="bi bi-lightning-fill" style="color:var(--warning);font-size:10px"></i>
{{ number_format($anime->trending_score, 1) }} puan
@else
{{ number_format($anime->recent_views ?? 0) }} izlenme
@endif
</div>
</div>
@if($anime->is_trending)
<span class="badge" style="background:var(--warning-dim);color:var(--warning);border:1px solid rgba(245,158,11,.3)">
<i class="bi bi-fire"></i> Trend
</span>
@else
<form method="POST" action="{{ route('admin.trending.toggle',$anime) }}">
@csrf
<button type="submit" class="btn btn-sm btn-outline-warning">
<i class="bi bi-plus-lg"></i> Ekle
</button>
</form>
@endif
</div>
@endforeach
</div>
</div>
{{-- Açıklama --}}
<div class="card">
<div class="card-body" style="padding:16px">
<div style="font-size:13px;font-weight:700;color:var(--text);margin-bottom:8px;display:flex;align-items:center;gap:7px">
<i class="bi bi-info-circle" style="color:var(--info)"></i> Nasıl Çalışır?
</div>
<ul style="font-size:12.5px;color:var(--text2);padding-left:16px;line-height:2;margin:0">
<li>Manuel liste boşsa otomatik trend (izlenme) gösterilir</li>
<li>Manuel liste doluysa seçtiğiniz animeler sırayla görünür</li>
<li>Sıralama yukarı/aşağı butonlarıyla değiştirilir</li>
</ul>
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
<script>
let searchTimer = null;
const CSRF = document.querySelector('meta[name=csrf-token]')?.content || '';
document.getElementById('trending-search').addEventListener('input', function() {
clearTimeout(searchTimer);
const q = this.value.trim();
const box = document.getElementById('search-results');
if (q.length < 2) { box.style.display='none'; return; }
searchTimer = setTimeout(async () => {
const r = await fetch(`/admin/trending/search?q=${encodeURIComponent(q)}`);
const d = await r.json();
box.style.display = 'block';
if (!d.results.length) {
box.innerHTML = '<div style="font-size:12.5px;color:var(--text2);padding:8px">Sonuç bulunamadı.</div>';
return;
}
box.innerHTML = d.results.map(a => `
<div class="search-result-item">
${a.cover ? `<img src="${a.cover}" style="width:30px;height:42px;object-fit:cover;border-radius:5px;flex-shrink:0">` : '<div style="width:30px;height:42px;background:var(--surface);border-radius:5px;flex-shrink:0"></div>'}
<div style="flex:1;min-width:0;font-size:13px;font-weight:600;color:var(--text)" class="text-truncate">${a.title}</div>
${a.is_trending
? '<span class="badge" style="background:var(--warning-dim);color:var(--warning)"><i class="bi bi-fire"></i> Trend</span>'
: `<form method="POST" action="/admin/trending/${a.id}/toggle" style="flex-shrink:0"><input type="hidden" name="_token" value="${CSRF}"><button class="btn btn-sm btn-outline-warning"><i class="bi bi-plus-lg"></i> Ekle</button></form>`
}
</div>
`).join('');
}, 350);
});
// ── Trend Skoru Hesapla ──────────────────────────────────────────────────────
async function computeScores() {
const btn = document.getElementById('btn-compute-scores');
const res = document.getElementById('compute-result');
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Hesaplanıyor...';
res.style.display = 'none';
try {
const r = await fetch('{{ route("admin.trending.compute-scores") }}', {
method: 'POST',
headers: { 'X-CSRF-TOKEN': CSRF, 'Accept': 'application/json' },
});
const d = await r.json();
res.style.display = 'block';
res.className = 'alert alert-success mb-3';
res.innerHTML = `<i class="bi bi-check-circle-fill me-2"></i><strong>${d.message}</strong>
<br><small>Anasayfa cache temizlendi. Sayfa yenileniyor...</small>`;
btn.innerHTML = '<i class="bi bi-check me-1"></i>Tamamlandı!';
setTimeout(() => location.reload(), 2000);
} catch(e) {
res.style.display = 'block';
res.className = 'alert alert-danger mb-3';
res.textContent = 'Hata: ' + e.message;
btn.disabled = false;
btn.innerHTML = '<i class="bi bi-lightning-fill me-1"></i>Trend Skorlarını Hesapla';
}
}
</script>
@endpush