2430 lines
142 KiB
PHP
2430 lines
142 KiB
PHP
@extends('admin.layouts.app')
|
||
@section('title','SEO Paneli')
|
||
@section('page-title','SEO Paneli')
|
||
|
||
@push('styles')
|
||
<style>
|
||
/* ── Score ring ─────────────────────────────── */
|
||
.seo-score-ring { position:relative; display:inline-flex; align-items:center; justify-content:center; }
|
||
.seo-score-ring svg { transform:rotate(-90deg); }
|
||
.seo-score-ring .score-text { position:absolute; text-align:center; }
|
||
.seo-score-ring .score-num { font-size:2.4rem; font-weight:800; line-height:1; }
|
||
.seo-score-ring .score-lbl { font-size:.7rem; text-transform:uppercase; letter-spacing:.1em; color:var(--text2); }
|
||
|
||
/* ── Tab nav ────────────────────────────────── */
|
||
.seo-tab-nav { display:flex; gap:4px; flex-wrap:wrap; border-bottom:1px solid var(--border); margin-bottom:24px; }
|
||
.seo-tab-btn { padding:8px 14px; border:none; background:transparent; color:var(--text2); font-size:.82rem;
|
||
border-bottom:2px solid transparent; cursor:pointer; border-radius:6px 6px 0 0; transition:.15s; white-space:nowrap; }
|
||
.seo-tab-btn:hover { background:var(--border); color:var(--text); }
|
||
.seo-tab-btn.active { color:var(--accent); border-bottom-color:var(--accent); background:var(--border); }
|
||
.seo-tab-pane { display:none; }
|
||
.seo-tab-pane.active { display:block; }
|
||
|
||
/* ── Check items ────────────────────────────── */
|
||
.check-item { display:flex; align-items:flex-start; gap:10px; padding:10px 14px; border-radius:8px; margin-bottom:6px; }
|
||
.check-item.pass { background:rgba(35,134,54,.1); border:1px solid rgba(35,134,54,.25); }
|
||
.check-item.fail { background:rgba(248,81,73,.08); border:1px solid rgba(248,81,73,.2); }
|
||
.check-icon { font-size:1.1rem; flex-shrink:0; margin-top:1px; }
|
||
.check-item.pass .check-icon { color:var(--success); }
|
||
.check-item.fail .check-icon { color:var(--danger); }
|
||
.check-msg { font-size:.85rem; }
|
||
.check-weight { margin-left:auto; font-size:.72rem; color:var(--text2); white-space:nowrap; flex-shrink:0; }
|
||
|
||
/* ── Cards ──────────────────────────────────── */
|
||
.section-card { background:var(--bg2); border:1px solid var(--border); border-radius:12px; margin-bottom:20px; overflow:hidden; }
|
||
.section-card-header { padding:14px 20px; border-bottom:1px solid var(--border); display:flex; align-items:center; gap:8px; }
|
||
.section-card-header h6 { margin:0; font-size:.88rem; font-weight:600; }
|
||
.section-card-body { padding:20px; }
|
||
.stat-mini { background:var(--bg2); border:1px solid var(--border); border-radius:10px; padding:14px 18px; }
|
||
.stat-mini .sm-val { font-size:1.8rem; font-weight:800; }
|
||
.stat-mini .sm-lbl { font-size:.75rem; color:var(--text2); }
|
||
|
||
/* ── Preview ────────────────────────────────── */
|
||
.preview-card { background:#010409; border:1px solid var(--border); border-radius:8px; padding:16px 20px; font-family:'Arial',sans-serif; }
|
||
.preview-url { color:#8ab4f8; font-size:.75rem; }
|
||
.preview-title { color:#8ab4f8; font-size:1.05rem; font-weight:400; margin:4px 0 2px; }
|
||
.preview-desc { color:#bdc1c6; font-size:.82rem; line-height:1.5; }
|
||
|
||
/* ── Misc ───────────────────────────────────── */
|
||
.robots-editor { font-family:'Courier New',monospace; font-size:.82rem; background:#010409; border-color:var(--border2); color:var(--text); resize:vertical; min-height:280px; }
|
||
.seo-field-help { font-size:.75rem; color:var(--text2); margin-top:4px; }
|
||
.char-counter { font-size:.72rem; text-align:right; margin-top:2px; }
|
||
.char-counter.ok { color:var(--success); } .char-counter.warn { color:#d29922; } .char-counter.bad { color:var(--danger); }
|
||
.ping-badge { display:inline-block; padding:2px 8px; border-radius:10px; font-size:.7rem; font-weight:600; }
|
||
.ping-badge.success { background:rgba(35,134,54,.25); color:var(--success); border:1px solid rgba(35,134,54,.3); }
|
||
.ping-badge.error { background:rgba(248,81,73,.15); color:var(--danger); border:1px solid rgba(248,81,73,.25); }
|
||
|
||
/* ── Keyword tag ────────────────────────────── */
|
||
.kwd-tag { display:inline-flex; align-items:center; gap:6px; background:var(--border); border:1px solid var(--border2); border-radius:20px; padding:4px 10px; font-size:.78rem; }
|
||
.kwd-diff-bar { height:4px; border-radius:2px; background:var(--border2); position:relative; }
|
||
.kwd-diff-fill { height:100%; border-radius:2px; }
|
||
|
||
/* ── Anime SEO table ────────────────────────── */
|
||
.seo-coverage-bar { height:6px; border-radius:3px; background:var(--border); overflow:hidden; }
|
||
.seo-coverage-fill { height:100%; border-radius:3px; background:linear-gradient(90deg,var(--accent),#f59e0b); }
|
||
|
||
/* ── PageSpeed score circles ─────────────────── */
|
||
.psi-score { display:inline-flex; flex-direction:column; align-items:center; justify-content:center; width:80px; height:80px; border-radius:50%; font-size:1.4rem; font-weight:800; }
|
||
.psi-score.good { border:4px solid var(--success); color:var(--success); }
|
||
.psi-score.average { border:4px solid #d29922; color:#d29922; }
|
||
.psi-score.poor { border:4px solid var(--danger); color:var(--danger); }
|
||
|
||
/* ── Redirect table ─────────────────────────── */
|
||
.redirect-row td { font-size:.82rem; vertical-align:middle; }
|
||
.redirect-row.inactive td { opacity:.5; }
|
||
|
||
/* ── AI Chat ─────────────────────────────────── */
|
||
.ai-msg { display:flex; gap:10px; }
|
||
.ai-msg.user { flex-direction:row-reverse; }
|
||
.ai-bubble { max-width:88%; padding:10px 14px; border-radius:12px; font-size:.84rem; line-height:1.55; }
|
||
.ai-msg.assistant .ai-bubble { background:var(--surface); border:1px solid var(--border); color:var(--text); border-radius:4px 12px 12px 12px; }
|
||
.ai-msg.user .ai-bubble { background:var(--accent); color:#fff; border-radius:12px 4px 12px 12px; }
|
||
.ai-msg .ai-avatar { width:28px; height:28px; border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:.75rem; flex-shrink:0; }
|
||
.ai-msg.assistant .ai-avatar { background:var(--border); color:var(--accent); }
|
||
.ai-msg.user .ai-avatar { background:var(--accent); color:#fff; }
|
||
.ai-typing span { width:6px; height:6px; border-radius:50%; background:var(--text2); display:inline-block; animation:typing 1.2s infinite; }
|
||
.ai-typing span:nth-child(2) { animation-delay:.2s; } .ai-typing span:nth-child(3) { animation-delay:.4s; }
|
||
@keyframes typing { 0%,60%,100%{transform:translateY(0);opacity:.6} 30%{transform:translateY(-5px);opacity:1} }
|
||
.ai-bubble strong { color:var(--text); } .ai-bubble b { color:var(--accent); }
|
||
.ai-bubble code { background:var(--bg2); padding:1px 5px; border-radius:3px; font-size:.78rem; color:var(--info); }
|
||
.ai-bubble ul,.ai-bubble ol { padding-left:18px; margin:6px 0; } .ai-bubble li { margin-bottom:2px; }
|
||
.ai-bubble h3,.ai-bubble h4 { color:var(--text); font-size:.9rem; margin:10px 0 4px; }
|
||
.ai-kw-badge { display:inline-flex; align-items:center; gap:4px; background:var(--border); border:1px solid var(--border2); border-radius:16px; padding:3px 10px; font-size:.75rem; margin:2px; cursor:pointer; transition:.15s; }
|
||
.ai-kw-badge:hover { background:var(--border2); border-color:var(--accent); }
|
||
|
||
/* ── Analytics Tab ───────────────────────────── */
|
||
/* Integration status bar */
|
||
.analytics-status-bar { background:var(--bg2); border:1px solid var(--border); border-radius:12px; padding:14px 20px; display:flex; align-items:center; gap:16px; flex-wrap:wrap; }
|
||
.asb-label { font-size:.75rem; font-weight:700; text-transform:uppercase; letter-spacing:.08em; color:var(--text2); white-space:nowrap; }
|
||
.asb-items { display:flex; gap:8px; flex-wrap:wrap; }
|
||
.asb-item { display:flex; align-items:center; gap:6px; background:var(--surface); border:1px solid var(--border); border-radius:20px; padding:4px 12px 4px 8px; font-size:.78rem; }
|
||
.asb-item.connected .asb-dot { width:8px;height:8px;border-radius:50%;background:var(--success);flex-shrink:0;box-shadow:0 0 6px rgba(63,185,80,.6); }
|
||
.asb-item.disconnected .asb-dot { width:8px;height:8px;border-radius:50%;background:var(--border2);flex-shrink:0; }
|
||
.asb-item.connected .asb-name { color:var(--text);font-weight:500; }
|
||
.asb-item.disconnected .asb-name { color:var(--text2); }
|
||
.asb-tag { color:var(--text2); font-size:.72rem; max-width:100px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
||
.asb-item.connected .asb-tag { color:var(--success); }
|
||
|
||
/* KPI Cards */
|
||
.analytics-kpi-card { background:var(--bg2); border:1px solid var(--border); border-radius:12px; padding:16px; display:flex; align-items:flex-start; gap:14px; height:100%; transition:.15s; }
|
||
.analytics-kpi-card:hover { border-color:var(--border2); transform:translateY(-1px); }
|
||
.kpi-icon { width:44px;height:44px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:1.2rem;flex-shrink:0; }
|
||
.kpi-body { flex:1; min-width:0; }
|
||
.kpi-val { font-size:1.8rem; font-weight:800; line-height:1.1; color:var(--text); }
|
||
.kpi-lbl { font-size:.73rem; color:var(--text2); margin-top:2px; text-transform:uppercase; letter-spacing:.06em; }
|
||
.kpi-trend { font-size:.72rem; margin-top:5px; display:inline-flex; align-items:center; gap:1px; padding:2px 7px; border-radius:10px; }
|
||
.kpi-trend.up { background:rgba(63,185,80,.1); color:var(--success); }
|
||
.kpi-trend.down { background:rgba(248,81,73,.08); color:var(--danger); }
|
||
|
||
/* Mini stats */
|
||
.analytics-mini-stat { background:var(--surface); border:1px solid var(--border); border-radius:8px; padding:10px 14px; text-align:center; }
|
||
.ams-val { font-size:1.4rem; font-weight:800; }
|
||
.ams-lbl { font-size:.7rem; color:var(--text2); text-transform:uppercase; letter-spacing:.05em; margin-top:2px; }
|
||
|
||
/* Redirect stats grid */
|
||
.redirect-stat-grid { display:grid; grid-template-columns:1fr 1fr; gap:12px; }
|
||
.rsg-item { background:var(--surface); border:1px solid var(--border); border-radius:8px; padding:14px; text-align:center; }
|
||
.rsg-val { font-size:2rem; font-weight:800; }
|
||
.rsg-lbl { font-size:.72rem; color:var(--text2); margin-top:3px; }
|
||
|
||
/* Quick tools grid */
|
||
.quick-tools-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(260px,1fr)); gap:10px; }
|
||
.qt-card { display:flex; align-items:center; gap:12px; background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:12px 14px; text-decoration:none; transition:.15s; }
|
||
.qt-card:hover { border-color:var(--border2); background:#1c2128; transform:translateX(2px); text-decoration:none; }
|
||
.qt-icon { width:40px;height:40px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:1.1rem;flex-shrink:0; }
|
||
.qt-body { flex:1; min-width:0; }
|
||
.qt-name { font-size:.84rem; font-weight:600; color:var(--text); }
|
||
.qt-desc { font-size:.73rem; color:var(--text2); margin-top:1px; }
|
||
.qt-status { font-size:.68rem; font-weight:600; padding:3px 8px; border-radius:10px; white-space:nowrap; }
|
||
.qt-status.on { background:rgba(63,185,80,.12); color:var(--success); border:1px solid rgba(63,185,80,.2); }
|
||
.qt-status.off { background:rgba(139,148,158,.08); color:var(--text2); border:1px solid var(--border); }
|
||
|
||
/* GSC guide box */
|
||
.gsc-guide-box { background:#010409; border:1px solid var(--border); border-radius:8px; padding:14px; }
|
||
.ggb-title { font-size:.8rem; font-weight:600; color:var(--text); margin-bottom:8px; }
|
||
.ggb-steps { padding-left:18px; margin:0; }
|
||
.ggb-steps li { font-size:.78rem; color:var(--text2); margin-bottom:5px; line-height:1.5; }
|
||
.ggb-steps a { color:var(--info); text-decoration:none; }
|
||
.ggb-steps a:hover { text-decoration:underline; }
|
||
.ggb-steps code { background:var(--surface); padding:1px 5px; border-radius:3px; font-size:.73rem; color:var(--info); word-break:break-all; }
|
||
</style>
|
||
@endpush
|
||
|
||
@section('content')
|
||
<div>
|
||
|
||
{{-- Header --}}
|
||
<div class="d-flex align-items-center justify-content-between mb-4">
|
||
<div>
|
||
<h4 class="mb-1 fw-bold">SEO Paneli</h4>
|
||
<p class="text-muted mb-0" style="font-size:.85rem">Arama motoru optimizasyonu · Anahtar kelimeler · Yönlendirmeler · PageSpeed</p>
|
||
</div>
|
||
<div class="d-flex gap-2">
|
||
<a href="{{ route('home') }}" target="_blank" class="btn btn-outline-secondary btn-sm"><i class="bi bi-box-arrow-up-right me-1"></i>Siteyi Gör</a>
|
||
<a href="/sitemap.xml" target="_blank" class="btn btn-outline-info btn-sm"><i class="bi bi-diagram-3 me-1"></i>Sitemap</a>
|
||
</div>
|
||
</div>
|
||
|
||
@if(session('success'))
|
||
<div class="alert alert-success d-flex align-items-center gap-2 mb-4"><i class="bi bi-check-circle-fill"></i>{{ session('success') }}</div>
|
||
@endif
|
||
|
||
{{-- SEO Score Summary --}}
|
||
<div class="row g-3 mb-4">
|
||
<div class="col-md-3">
|
||
<div class="section-card h-100">
|
||
<div class="section-card-body d-flex flex-column align-items-center justify-content-center py-4">
|
||
<div class="seo-score-ring mb-3">
|
||
@php $sc = $audit['score']; $color = $sc>=80?'var(--success)':($sc>=60?'#d29922':'var(--danger)'); $circ = round(2*pi()*52*$sc/100,1); @endphp
|
||
<svg width="120" height="120" viewBox="0 0 120 120">
|
||
<circle cx="60" cy="60" r="52" fill="none" stroke="var(--border)" stroke-width="10"/>
|
||
<circle cx="60" cy="60" r="52" fill="none" stroke="{{ $color }}" stroke-width="10" stroke-dasharray="{{ $circ }} 999" stroke-linecap="round"/>
|
||
</svg>
|
||
<div class="score-text">
|
||
<div class="score-num" style="color:{{ $color }}">{{ $sc }}</div>
|
||
<div class="score-lbl">/ 100</div>
|
||
</div>
|
||
</div>
|
||
<div class="fw-semibold" style="font-size:.9rem">SEO Skoru</div>
|
||
<div style="font-size:.75rem;color:var(--text2)">@if($sc>=80)Mükemmel @elseif($sc>=60)Geliştirilmeli @else Kritik Sorunlar @endif</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-3">
|
||
<div class="stat-mini h-100 d-flex flex-column justify-content-center">
|
||
<div class="sm-val text-success">{{ $audit['pass_count'] }}</div>
|
||
<div class="sm-lbl">Geçen Kontrol</div>
|
||
<div class="mt-2" style="font-size:.75rem;color:var(--text2)">{{ $audit['totals']['total'] }} anime yayında</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-3">
|
||
<div class="stat-mini h-100 d-flex flex-column justify-content-center">
|
||
<div class="sm-val text-danger">{{ $audit['fail_count'] }}</div>
|
||
<div class="sm-lbl">Başarısız Kontrol</div>
|
||
<div class="mt-2" style="font-size:.75rem;color:var(--text2)">{{ $audit['totals']['noSeoTitle'] ?? 0 }} animede SEO başlık eksik</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-3">
|
||
<div class="stat-mini h-100 d-flex flex-column justify-content-center">
|
||
@php $cov = $animeSeoCoverage; $pct = $cov['total']>0?round($cov['has_seo_title']/$cov['total']*100):0; @endphp
|
||
<div class="sm-val" style="color:var(--info)">{{ $pct }}%</div>
|
||
<div class="sm-lbl">Anime SEO Kapsama</div>
|
||
<div class="mt-2 seo-coverage-bar"><div class="seo-coverage-fill" style="width:{{ $pct }}%"></div></div>
|
||
<div class="mt-1" style="font-size:.72rem;color:var(--text2)">{{ $cov['has_seo_title'] }}/{{ $cov['total'] }} başlık · {{ $cov['has_seo_desc'] }}/{{ $cov['total'] }} açıklama</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Tab Nav --}}
|
||
<div class="seo-tab-nav">
|
||
<button class="seo-tab-btn active" data-tab="meta"> <i class="bi bi-tags me-1"></i>Meta</button>
|
||
<button class="seo-tab-btn" data-tab="keywords"> <i class="bi bi-search me-1"></i>Anahtar Kelimeler</button>
|
||
<button class="seo-tab-btn" data-tab="anime-seo"> <i class="bi bi-collection-play me-1"></i>Anime SEO</button>
|
||
<button class="seo-tab-btn" data-tab="social"> <i class="bi bi-share me-1"></i>Sosyal Medya</button>
|
||
<button class="seo-tab-btn" data-tab="schema"> <i class="bi bi-braces me-1"></i>Yapısal Veri</button>
|
||
<button class="seo-tab-btn" data-tab="sitemap"> <i class="bi bi-diagram-3 me-1"></i>Sitemap</button>
|
||
<button class="seo-tab-btn" data-tab="robots"> <i class="bi bi-robot me-1"></i>Robots.txt</button>
|
||
<button class="seo-tab-btn" data-tab="redirects"> <i class="bi bi-signpost-split me-1"></i>Yönlendirmeler</button>
|
||
<button class="seo-tab-btn" data-tab="google"> <i class="bi bi-google me-1"></i>Google Araçları</button>
|
||
<button class="seo-tab-btn" data-tab="pagespeed"> <i class="bi bi-speedometer2 me-1"></i>PageSpeed</button>
|
||
<button class="seo-tab-btn" data-tab="audit"> <i class="bi bi-clipboard-check me-1"></i>Denetim</button>
|
||
<button class="seo-tab-btn" data-tab="ai"> <i class="bi bi-stars me-1"></i>AI Asistan</button>
|
||
</div>
|
||
|
||
{{-- ═══════ TAB 1: META ═══════ --}}
|
||
<form method="POST" action="{{ route('admin.seo.update') }}" id="seo-meta-form">
|
||
@csrf
|
||
<div class="seo-tab-pane active" id="tab-meta">
|
||
<div class="row g-4">
|
||
<div class="col-lg-7">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-type"></i><h6>Başlık Ayarları</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="mb-3">
|
||
<label class="form-label">Site Adı</label>
|
||
<input type="text" name="seo_site_name" class="form-control" value="{{ $settings['seo_site_name'] ?? 'Animexe' }}">
|
||
<div class="seo-field-help">OG etiketlerinde ve sayfa başlıklarında kullanılır.</div>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">Başlık Şablonu</label>
|
||
<input type="text" name="seo_title_template" class="form-control" value="{{ $settings['seo_title_template'] ?? '%s — Animexe' }}">
|
||
<div class="seo-field-help"><code>%s</code> = sayfa adı. Örn: <em>Naruto — Animexe | Türkçe Anime İzle</em></div>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">Anasayfa Başlığı</label>
|
||
<input type="text" name="seo_home_title" class="form-control" value="{{ html_entity_decode($settings['seo_home_title'] ?? '', ENT_QUOTES) }}" id="inp_home_title" maxlength="70" oninput="updateCounter(this,'ctr_home_title',50,60,70); updatePreview()">
|
||
<div class="d-flex justify-content-between">
|
||
<div class="seo-field-help">50–60 karakter ideal.</div>
|
||
<div class="char-counter" id="ctr_home_title">{{ strlen($settings['seo_home_title'] ?? '') }}/70</div>
|
||
</div>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">Anasayfa Meta Açıklaması</label>
|
||
<textarea name="seo_home_description" class="form-control" rows="3" id="inp_home_desc" maxlength="320" oninput="updateCounter(this,'ctr_home_desc',120,160,320); updatePreview()">{{ $settings['seo_home_description'] ?? '' }}</textarea>
|
||
<div class="d-flex justify-content-between">
|
||
<div class="seo-field-help">120–160 karakter ideal.</div>
|
||
<div class="char-counter" id="ctr_home_desc">{{ strlen($settings['seo_home_description'] ?? '') }}/320</div>
|
||
</div>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">Anasayfa Anahtar Kelimeler</label>
|
||
<textarea name="seo_home_keywords" class="form-control" rows="2">{{ $settings['seo_home_keywords'] ?? '' }}</textarea>
|
||
<div class="seo-field-help">Virgülle ayrılmış. Ör: <em>anime izle, türkçe anime</em></div>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">Canonical Domain</label>
|
||
<input type="url" name="seo_canonical_domain" class="form-control" value="{{ $settings['seo_canonical_domain'] ?? '' }}" placeholder="https://animexe.com">
|
||
<div class="seo-field-help">Trailing slash olmadan. Canonical URL'ler için kullanılır.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-eye-slash text-warning"></i><h6>Noindex Kuralları</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="mb-2 d-flex align-items-center gap-3">
|
||
<div class="form-check form-switch mb-0">
|
||
<input type="checkbox" class="form-check-input" role="switch" name="seo_noindex_search" id="ni_search" value="1" {{ ($settings['seo_noindex_search']??'1')==='1'?'checked':'' }}>
|
||
<label class="form-check-label" for="ni_search">Arama Sayfası noindex</label>
|
||
</div>
|
||
<span class="badge bg-warning text-dark" style="font-size:.68rem">Önerilen</span>
|
||
</div>
|
||
<div class="mb-2 form-check form-switch">
|
||
<input type="checkbox" class="form-check-input" role="switch" name="seo_noindex_profile" id="ni_profile" value="1" {{ ($settings['seo_noindex_profile']??'1')==='1'?'checked':'' }}>
|
||
<label class="form-check-label" for="ni_profile">Profil & Kişisel Sayfalar noindex</label>
|
||
</div>
|
||
<div class="mb-2 form-check form-switch">
|
||
<input type="checkbox" class="form-check-input" role="switch" name="seo_noindex_watch" id="ni_watch" value="1" {{ ($settings['seo_noindex_watch']??'0')==='1'?'checked':'' }}>
|
||
<label class="form-check-label" for="ni_watch">İzleme (Player) Sayfaları noindex</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="col-lg-5">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-google me-1"></i><h6>Google Arama Önizlemesi</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="preview-card">
|
||
<div class="preview-url">animexe.com</div>
|
||
<div class="preview-title" id="prev_title">{{ $settings['seo_home_title'] ?? 'Animexe — Türkçe Anime İzle' }}</div>
|
||
<div class="preview-desc" id="prev_desc">{{ Str::limit($settings['seo_home_description']??'',155) }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-phone me-1"></i><h6>Mobil Snippet</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="preview-card" style="max-width:300px">
|
||
<div style="font-size:.65rem;color:var(--text2)">animexe.com ›</div>
|
||
<div class="preview-title" style="font-size:.9rem" id="prev_title_mob">{{ $settings['seo_home_title']??'' }}</div>
|
||
<div class="preview-desc" style="font-size:.75rem" id="prev_desc_mob">{{ Str::limit($settings['seo_home_description']??'',100) }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-bar-chart me-1"></i><h6>Karakter Kılavuzu</h6></div>
|
||
<div class="section-card-body">
|
||
@foreach(['Sayfa Başlığı'=>['guide_title','bar_title',50,60,70],'Meta Açıklama'=>['guide_desc','bar_desc',120,160,320]] as $lbl=>$cfg)
|
||
<div class="mb-3">
|
||
<div class="d-flex justify-content-between mb-1" style="font-size:.78rem">
|
||
<span>{{ $lbl }}</span><span id="{{ $cfg[0] }}" class="text-muted">0/{{ $cfg[4] }}</span>
|
||
</div>
|
||
<div class="progress" style="height:6px"><div class="progress-bar bg-success" id="{{ $cfg[1] }}" style="width:0%"></div></div>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<button type="submit" class="btn btn-primary px-4"><i class="bi bi-save me-2"></i>Meta Ayarlarını Kaydet</button>
|
||
</div>
|
||
</form>{{-- #seo-meta-form --}}
|
||
|
||
{{-- ═══════ TAB 2: ANAHTAR KELİMELER ═══════ --}}
|
||
<div class="seo-tab-pane" id="tab-keywords">
|
||
<div class="row g-4">
|
||
<div class="col-lg-5">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-plus-circle text-success"></i><h6>Yeni Anahtar Kelime Ekle</h6></div>
|
||
<div class="section-card-body">
|
||
<form method="POST" action="{{ route('admin.seo.keywords.store') }}">
|
||
@csrf
|
||
<div class="mb-3">
|
||
<label class="form-label">Anahtar Kelime <span class="text-danger">*</span></label>
|
||
<input type="text" name="keyword" class="form-control" placeholder="anime izle türkçe" required>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">Hedef URL</label>
|
||
<input type="text" name="target_url" class="form-control" placeholder="/anime/naruto">
|
||
<div class="seo-field-help">Bu kelimeyi optimize etmek istediğiniz sayfa</div>
|
||
</div>
|
||
<div class="row g-2 mb-3">
|
||
<div class="col">
|
||
<label class="form-label">Aylık Arama Hacmi</label>
|
||
<input type="number" name="search_volume" class="form-control" placeholder="10000" min="0">
|
||
</div>
|
||
<div class="col">
|
||
<label class="form-label">Rekabet (0–100)</label>
|
||
<input type="number" name="difficulty" class="form-control" placeholder="45" min="0" max="100">
|
||
<div class="seo-field-help">0=kolay, 100=çok zor</div>
|
||
</div>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">Notlar</label>
|
||
<textarea name="notes" class="form-control" rows="2" placeholder="Bu kelime için stratejik notlar..."></textarea>
|
||
</div>
|
||
<button type="submit" class="btn btn-success w-100"><i class="bi bi-plus me-1"></i>Ekle</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="col-lg-7">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-table"></i><h6>Anahtar Kelime Listesi ({{ $keywords->count() }})</h6></div>
|
||
@if($keywords->isEmpty())
|
||
<div class="section-card-body text-center text-muted py-5">
|
||
<i class="bi bi-search" style="font-size:2rem;opacity:.3;display:block;margin-bottom:8px"></i>
|
||
Henüz anahtar kelime eklenmedi. Sol taraftan ekleyin.
|
||
</div>
|
||
@else
|
||
<div class="table-responsive">
|
||
<table class="table table-sm mb-0">
|
||
<thead class="table-dark">
|
||
<tr>
|
||
<th>Kelime</th>
|
||
<th>Hedef URL</th>
|
||
<th style="width:90px">Hacim</th>
|
||
<th style="width:80px">Rekabet</th>
|
||
<th style="width:60px"></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
@foreach($keywords as $kw)
|
||
<tr>
|
||
<td>
|
||
<div class="fw-semibold" style="font-size:.85rem">{{ $kw->keyword }}</div>
|
||
@if($kw->notes)<div style="font-size:.72rem;color:var(--text2)">{{ Str::limit($kw->notes,60) }}</div>@endif
|
||
</td>
|
||
<td>
|
||
@if($kw->target_url)
|
||
<a href="{{ $kw->target_url }}" target="_blank" style="font-size:.78rem;color:var(--info)">{{ Str::limit($kw->target_url,30) }}</a>
|
||
@else<span class="text-muted small">—</span>@endif
|
||
</td>
|
||
<td>
|
||
@if($kw->search_volume !== null)
|
||
<span class="badge bg-info text-dark" style="font-size:.72rem">{{ number_format($kw->search_volume) }}</span>
|
||
@else<span class="text-muted small">—</span>@endif
|
||
</td>
|
||
<td>
|
||
@if($kw->difficulty !== null)
|
||
@php $dc = $kw->difficulty<=33?'var(--success)':($kw->difficulty<=66?'#d29922':'var(--danger)'); @endphp
|
||
<div style="font-size:.8rem;color:{{ $dc }};font-weight:600">{{ $kw->difficulty }}</div>
|
||
<div class="kwd-diff-bar mt-1"><div class="kwd-diff-fill" style="width:{{ $kw->difficulty }}%;background:{{ $dc }}"></div></div>
|
||
@else<span class="text-muted small">—</span>@endif
|
||
</td>
|
||
<td>
|
||
<form method="POST" action="{{ route('admin.seo.keywords.destroy', $kw) }}" onsubmit="return confirm('Sil?')">
|
||
@csrf @method('DELETE')
|
||
<button class="btn btn-sm btn-outline-danger p-1"><i class="bi bi-trash" style="font-size:.75rem"></i></button>
|
||
</form>
|
||
</td>
|
||
</tr>
|
||
@endforeach
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
@endif
|
||
</div>
|
||
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-lightbulb text-warning"></i><h6>Sıralama İpuçları</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="row g-3">
|
||
@foreach([
|
||
['bi-1-circle','Anime Türkiye Odaklı','anime izle, türkçe anime, ücretsiz anime gibi yerel arama kelimelerine odaklanın'],
|
||
['bi-2-circle','Long-tail Kelimeler','naruto türkçe altyazılı izle, attack on titan dublaj gibi uzun kuyruklu kelimeler daha az rekabetçi'],
|
||
['bi-3-circle','İçerik Sıklığı','Popüler animeler için haftada en az 1 bölüm ekleyin. Google taze içeriği sever'],
|
||
['bi-4-circle','Internal Linking','Anime sayfalarında benzer türlere link verin. Dahili bağlantı SEO skorunu artırır'],
|
||
] as $tip)
|
||
<div class="col-md-6">
|
||
<div style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:12px">
|
||
<div class="d-flex align-items-center gap-2 mb-1">
|
||
<i class="bi {{ $tip[0] }}" style="color:var(--accent)"></i>
|
||
<span style="font-size:.82rem;font-weight:600">{{ $tip[1] }}</span>
|
||
</div>
|
||
<div style="font-size:.75rem;color:var(--text2)">{{ $tip[2] }}</div>
|
||
</div>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ═══════ TAB 3: ANİME SEO ═══════ --}}
|
||
<div class="seo-tab-pane" id="tab-anime-seo">
|
||
|
||
{{-- ── Toplu Doldurma Paneli ── --}}
|
||
<div class="section-card mb-4" id="bulk-fill-panel">
|
||
<div class="card-header d-flex align-items-center gap-2">
|
||
<i class="bi bi-lightning-fill" style="color:var(--warning)"></i>
|
||
<h6 class="mb-0">Toplu AI Doldurma</h6>
|
||
<span class="badge bg-secondary ms-auto" id="bf-coverage-badge">Yükleniyor...</span>
|
||
</div>
|
||
<div class="card-body">
|
||
|
||
{{-- Coverage istatistikleri --}}
|
||
<div id="bf-stats" style="display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-bottom:16px">
|
||
<div class="text-center p-2" style="background:var(--bg);border:1px solid var(--border);border-radius:8px">
|
||
<div style="font-size:22px;font-weight:700;color:var(--success)" id="bf-pct-seo">—</div>
|
||
<div style="font-size:11px;color:var(--text2)">SEO Başlığı Var</div>
|
||
</div>
|
||
<div class="text-center p-2" style="background:var(--bg);border:1px solid var(--border);border-radius:8px">
|
||
<div style="font-size:22px;font-weight:700;color:var(--info)" id="bf-pct-desc">—</div>
|
||
<div style="font-size:11px;color:var(--text2)">Açıklama Var</div>
|
||
</div>
|
||
<div class="text-center p-2" style="background:var(--bg);border:1px solid var(--border);border-radius:8px">
|
||
<div style="font-size:22px;font-weight:700" id="bf-needs-seo">—</div>
|
||
<div style="font-size:11px;color:var(--text2)">SEO Eksik Anime</div>
|
||
</div>
|
||
<div class="text-center p-2" style="background:var(--bg);border:1px solid var(--border);border-radius:8px">
|
||
<div style="font-size:22px;font-weight:700" id="bf-needs-meta">—</div>
|
||
<div style="font-size:11px;color:var(--text2)">Meta Eksik Anime</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Aksiyon butonları --}}
|
||
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:14px">
|
||
|
||
<div style="border:1px solid var(--border);border-radius:8px;padding:12px">
|
||
<div style="font-weight:600;font-size:13px;margin-bottom:4px">
|
||
<i class="bi bi-lightning" style="color:var(--warning)"></i> Hızlı SEO
|
||
</div>
|
||
<div style="font-size:11px;color:var(--text2);margin-bottom:8px">Template kullanır, AI çağrısı yok. Tüm anime birkaç saniyede tamamlanır.</div>
|
||
<button class="btn btn-sm btn-outline-warning w-100" onclick="startBulkFill('template_seo')">
|
||
<i class="bi bi-stars me-1"></i>Tümüne Uygula
|
||
</button>
|
||
</div>
|
||
|
||
<div style="border:1px solid var(--border);border-radius:8px;padding:12px">
|
||
<div style="font-weight:600;font-size:13px;margin-bottom:4px">
|
||
<i class="bi bi-robot" style="color:var(--info)"></i> AI SEO
|
||
</div>
|
||
<div style="font-size:11px;color:var(--text2);margin-bottom:8px">DeepSeek ile her anime için özgün SEO başlığı ve açıklama üretir.</div>
|
||
<button class="btn btn-sm btn-outline-info w-100" onclick="startBulkFill('ai_seo')">
|
||
<i class="bi bi-robot me-1"></i>AI ile Uygula
|
||
</button>
|
||
</div>
|
||
|
||
<div style="border:1px solid var(--border);border-radius:8px;padding:12px">
|
||
<div style="font-weight:600;font-size:13px;margin-bottom:4px">
|
||
<i class="bi bi-magic" style="color:var(--success)"></i> Tam Doldurma
|
||
</div>
|
||
<div style="font-size:11px;color:var(--text2);margin-bottom:8px">Açıklama + Yıl + Stüdyo + Türler + SEO başlığı — her şeyi AI ile doldurur.</div>
|
||
<button class="btn btn-sm btn-outline-success w-100" onclick="startBulkFill('ai_all')">
|
||
<i class="bi bi-magic me-1"></i>Hepsini Doldur
|
||
</button>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div class="d-flex gap-2 mb-2">
|
||
<label class="d-flex align-items-center gap-2" style="font-size:12px;cursor:pointer">
|
||
<input type="checkbox" id="bf-force"> Dolu alanları da üzerine yaz (force)
|
||
</label>
|
||
<button class="btn btn-sm btn-danger ms-auto d-none" id="bf-stop-btn" onclick="stopBulkFill()">
|
||
<i class="bi bi-stop-fill me-1"></i>Durdur
|
||
</button>
|
||
</div>
|
||
|
||
{{-- Progress alanı --}}
|
||
<div id="bf-progress-area" style="display:none">
|
||
<div style="display:flex;justify-content:space-between;font-size:12px;color:var(--text2);margin-bottom:4px">
|
||
<span id="bf-progress-label">İşleniyor...</span>
|
||
<span id="bf-progress-count">0 / 0</span>
|
||
</div>
|
||
<div style="height:10px;background:var(--bg);border-radius:5px;overflow:hidden">
|
||
<div id="bf-progress-bar" style="height:100%;background:var(--accent);border-radius:5px;transition:width .3s;width:0%"></div>
|
||
</div>
|
||
<div id="bf-log" style="margin-top:8px;font-size:11px;color:var(--text2);font-family:monospace;max-height:80px;overflow-y:auto"></div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ── Tablo başlığı ── --}}
|
||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||
<div>
|
||
<h6 class="mb-1">Anime SEO Başlıkları & Açıklamaları</h6>
|
||
<p class="text-muted mb-0" style="font-size:.8rem">Tek tek anime için düzenle ve kaydet. Toplu işlem için yukarıdaki paneli kullan.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<form method="POST" action="{{ route('admin.seo.anime-bulk') }}" id="anime-seo-form">
|
||
@csrf
|
||
<div class="section-card">
|
||
<div class="table-responsive">
|
||
<table class="table table-sm mb-0">
|
||
<thead class="table-dark">
|
||
<tr>
|
||
<th style="width:200px">Anime</th>
|
||
<th>SEO Başlığı <small class="text-muted">(max 70 karakter)</small></th>
|
||
<th>Meta Açıklaması <small class="text-muted">(max 160 karakter)</small></th>
|
||
<th style="width:80px">Anahtar Kelimeler</th>
|
||
<th style="width:50px"></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
@foreach($animes as $a)
|
||
<tr id="anime-row-{{ $a->id }}">
|
||
<input type="hidden" name="animes[{{ $loop->index }}][id]" value="{{ $a->id }}">
|
||
<td>
|
||
<div class="fw-semibold" style="font-size:.82rem">{{ Str::limit($a->title,30) }}</div>
|
||
<div style="font-size:.7rem;color:var(--text2)">/anime/{{ $a->slug }}</div>
|
||
@if(!$a->seo_title)
|
||
<span class="badge bg-danger" style="font-size:.65rem">SEO eksik</span>
|
||
@else
|
||
<span class="badge bg-success" style="font-size:.65rem">SEO var</span>
|
||
@endif
|
||
</td>
|
||
<td>
|
||
<input type="text" name="animes[{{ $loop->index }}][seo_title]"
|
||
class="form-control form-control-sm seo-title-inp"
|
||
data-id="{{ $a->id }}"
|
||
value="{{ $a->seo_title ?? '' }}"
|
||
maxlength="100"
|
||
placeholder="{{ Str::limit($a->title.' — Türkçe Anime | Animexe',70) }}">
|
||
</td>
|
||
<td>
|
||
<textarea name="animes[{{ $loop->index }}][seo_meta_desc]"
|
||
class="form-control form-control-sm"
|
||
rows="2"
|
||
maxlength="320"
|
||
placeholder="Bu anime hakkında kısa açıklama...">{{ $a->seo_meta_desc ?? '' }}</textarea>
|
||
</td>
|
||
<td>
|
||
<input type="text" name="animes[{{ $loop->index }}][seo_keywords]"
|
||
class="form-control form-control-sm"
|
||
value="{{ $a->seo_keywords ?? '' }}"
|
||
placeholder="anahtar,kelimeler">
|
||
</td>
|
||
<td>
|
||
<button type="button" class="btn btn-sm btn-outline-secondary p-1 btn-auto-seo" data-id="{{ $a->id }}" title="Otomatik Oluştur">
|
||
<i class="bi bi-stars" style="font-size:.75rem"></i>
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
@endforeach
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="p-3 border-top border-secondary d-flex align-items-center justify-content-between">
|
||
<div>{{ $animes->links() }}</div>
|
||
<button type="submit" class="btn btn-primary"><i class="bi bi-save me-1"></i>Bu Sayfayı Kaydet</button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
{{-- ═══════ TAB 4: SOSYAL MEDYA ═══════ --}}
|
||
<form method="POST" action="{{ route('admin.seo.update') }}">
|
||
@csrf
|
||
<div class="seo-tab-pane" id="tab-social">
|
||
<div class="row g-4">
|
||
<div class="col-lg-6">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-facebook text-primary me-1"></i><h6>Open Graph (Facebook / WhatsApp / LinkedIn)</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="mb-3">
|
||
<label class="form-label">Varsayılan OG Görseli</label>
|
||
<input type="text" name="seo_og_image" class="form-control" value="{{ $settings['seo_og_image'] ?? '' }}" placeholder="/images/og-animexe.jpg">
|
||
<div class="seo-field-help">1200×630px önerilir. HTTPS URL veya /public altı yol.</div>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">Facebook App ID</label>
|
||
<input type="text" name="seo_facebook_app_id" class="form-control" value="{{ $settings['seo_facebook_app_id'] ?? '' }}" placeholder="123456789012345">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-twitter-x me-1"></i><h6>Twitter / X Card</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="mb-3">
|
||
<label class="form-label">Twitter Kullanıcı Adı</label>
|
||
<div class="input-group">
|
||
<span class="input-group-text">@</span>
|
||
<input type="text" name="seo_twitter_site" class="form-control" value="{{ ltrim($settings['seo_twitter_site'] ?? '', '@') }}" placeholder="animexecom">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-lg-6">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-building me-1"></i><h6>Organizasyon Bilgileri (Schema)</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="mb-3">
|
||
<label class="form-label">Logo URL</label>
|
||
<input type="text" name="seo_org_logo" class="form-control" value="{{ $settings['seo_org_logo'] ?? '' }}">
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">Twitter URL</label>
|
||
<input type="text" name="seo_org_twitter" class="form-control" value="{{ $settings['seo_org_twitter'] ?? '' }}" placeholder="https://twitter.com/animexecom">
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">Facebook URL</label>
|
||
<input type="text" name="seo_org_facebook" class="form-control" value="{{ $settings['seo_org_facebook'] ?? '' }}" placeholder="https://facebook.com/animexecom">
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">Instagram URL</label>
|
||
<input type="text" name="seo_org_instagram" class="form-control" value="{{ $settings['seo_org_instagram'] ?? '' }}" placeholder="https://instagram.com/animexecom">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<button type="submit" class="btn btn-primary px-4"><i class="bi bi-save me-2"></i>Sosyal Medya Ayarlarını Kaydet</button>
|
||
</div>
|
||
</form>{{-- social form --}}
|
||
|
||
{{-- ═══════ TAB 5: YAPISAL VERİ ═══════ --}}
|
||
<form method="POST" action="{{ route('admin.seo.update') }}">
|
||
@csrf
|
||
<input type="hidden" name="_seo_section" value="schema">
|
||
<div class="seo-tab-pane" id="tab-schema">
|
||
<div class="row g-4">
|
||
<div class="col-lg-6">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-braces"></i><h6>Schema.org Ayarları</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="mb-3 d-flex align-items-center gap-3">
|
||
<div class="form-check form-switch mb-0">
|
||
<input type="checkbox" class="form-check-input" role="switch" name="seo_enable_schema" id="sch_main" value="1" {{ ($settings['seo_enable_schema']??'1')==='1'?'checked':'' }}>
|
||
<label class="form-check-label" for="sch_main">Schema.org İşaretleme Aktif</label>
|
||
</div>
|
||
<span class="badge bg-success" style="font-size:.68rem">Önerilen</span>
|
||
</div>
|
||
<div class="mb-3 form-check form-switch">
|
||
<input type="checkbox" class="form-check-input" role="switch" name="seo_enable_breadcrumb" id="sch_bc" value="1" {{ ($settings['seo_enable_breadcrumb']??'1')==='1'?'checked':'' }}>
|
||
<label class="form-check-label" for="sch_bc">BreadcrumbList Schema</label>
|
||
</div>
|
||
<div class="mb-3 d-flex align-items-center gap-3">
|
||
<div class="form-check form-switch mb-0">
|
||
<input type="checkbox" class="form-check-input" role="switch" name="seo_enable_faq_schema" id="sch_faq" value="1" {{ ($settings['seo_enable_faq_schema']??'1')==='1'?'checked':'' }}>
|
||
<label class="form-check-label" for="sch_faq">FAQ Schema (Rich Snippet)</label>
|
||
</div>
|
||
<span class="badge bg-info text-dark" style="font-size:.68rem">Rich Snippet</span>
|
||
</div>
|
||
<div class="mb-3 d-flex align-items-center gap-3">
|
||
<div class="form-check form-switch mb-0">
|
||
<input type="checkbox" class="form-check-input" role="switch" name="seo_enable_video_schema" id="sch_vid" value="1" {{ ($settings['seo_enable_video_schema']??'1')==='1'?'checked':'' }}>
|
||
<label class="form-check-label" for="sch_vid">VideoObject Schema</label>
|
||
</div>
|
||
<span class="badge bg-info text-dark" style="font-size:.68rem">Rich Snippet</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-lg-6">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-info-circle text-info"></i><h6>Schema Türleri Hakkında</h6></div>
|
||
<div class="section-card-body">
|
||
@foreach([
|
||
['Organization','Site kimliği için. Google\'ın sitenizi tanımasını sağlar.','bg-success'],
|
||
['TVSeries / Movie','Her anime için. IMDB benzeri rich snippet\'ler oluşturur.','bg-success'],
|
||
['BreadcrumbList','Navigasyon yolu. Arama sonuçlarında alt bağlantılar gösterir.','bg-info text-dark'],
|
||
['VideoObject','Bölüm sayfaları için. Video thumbnails arama sonuçlarında çıkar.','bg-warning text-dark'],
|
||
['FAQPage','Anime SSS bölümü. Arama sonuçlarında soru-cevap kutucukları gösterir.','bg-warning text-dark'],
|
||
] as $s)
|
||
<div class="d-flex align-items-start gap-2 mb-3">
|
||
<span class="badge {{ $s[2] }}" style="font-size:.72rem;white-space:nowrap;margin-top:2px">{{ $s[0] }}</span>
|
||
<span style="font-size:.8rem;color:var(--text2)">{{ $s[1] }}</span>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<button type="submit" class="btn btn-primary px-4"><i class="bi bi-save me-2"></i>Yapısal Veri Ayarlarını Kaydet</button>
|
||
</div>
|
||
|
||
{{-- ═══════ TAB 6: SİTEMAP ═══════ --}}
|
||
<div class="seo-tab-pane" id="tab-sitemap">
|
||
<div class="row g-4">
|
||
<div class="col-lg-5">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-diagram-3"></i><h6>Sitemap İstatistikleri</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="row g-2 mb-3">
|
||
@foreach([['Anime','bi-play-circle',$sitemapStats['anime_count'],'#58a6ff'],['Tür','bi-tags',$sitemapStats['genre_count'],'var(--success)'],['Statik','bi-file-text',2,'var(--text2)']] as $s)
|
||
<div class="col-4 text-center">
|
||
<div style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:12px 8px">
|
||
<i class="bi {{ $s[1] }}" style="font-size:1.2rem;color:{{ $s[3] }}"></i>
|
||
<div style="font-size:1.4rem;font-weight:800;color:{{ $s[3] }}">{{ $s[2] }}</div>
|
||
<div style="font-size:.72rem;color:var(--text2)">{{ $s[0] }}</div>
|
||
</div>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
@if($sitemapStats['last_updated'])
|
||
<div class="text-muted" style="font-size:.78rem"><i class="bi bi-clock me-1"></i>Son güncelleme: {{ $sitemapStats['last_updated'] }}</div>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-send"></i><h6>Arama Motorlarına Bildir</h6></div>
|
||
<div class="section-card-body">
|
||
@if(session('ping_results'))
|
||
<div class="d-flex gap-2 mb-3">
|
||
@foreach(session('ping_results') as $e=>$r)
|
||
<span class="ping-badge {{ $r }}"><i class="bi bi-{{ $r==='success'?'check':'x' }}-circle me-1"></i>{{ ucfirst($e) }}</span>
|
||
@endforeach
|
||
</div>
|
||
@endif
|
||
<form method="POST" action="{{ route('admin.seo.ping') }}">
|
||
@csrf
|
||
<button type="submit" class="btn btn-outline-info w-100">
|
||
<i class="bi bi-broadcast me-1"></i>Google & Bing'e Bildirim Gönder
|
||
</button>
|
||
</form>
|
||
<div class="seo-field-help mt-2">sitemap.xml güncellendiğinde arama motorlarını haberdar eder.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-lg-7">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-file-earmark-code"></i><h6>Sitemap Önizleme</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="sitemap-url-list" style="max-height:400px;overflow-y:auto;background:#010409;border:1px solid var(--border);border-radius:8px">
|
||
@php $previewAnimes = \App\Models\Anime::where('is_published',true)->orderByDesc('updated_at')->take(15)->get(['title','slug','updated_at']); @endphp
|
||
@foreach($previewAnimes as $pa)
|
||
<div style="padding:8px 14px;border-bottom:1px solid var(--border);font-size:.78rem;display:flex;justify-content:space-between">
|
||
<span style="color:var(--info)">/anime/{{ $pa->slug }}</span>
|
||
<span style="color:var(--text2)">{{ $pa->updated_at?->format('Y-m-d') }}</span>
|
||
</div>
|
||
@endforeach
|
||
<div style="padding:8px 14px;border-bottom:1px solid var(--border);font-size:.78rem;color:var(--text2)">... ve daha fazlası</div>
|
||
</div>
|
||
<div class="mt-2 text-end">
|
||
<a href="/sitemap.xml" target="_blank" class="btn btn-sm btn-outline-secondary">
|
||
<i class="bi bi-box-arrow-up-right me-1"></i>Tüm Sitemap'ı Gör
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ═══════ TAB 7: ROBOTS.TXT ═══════ --}}
|
||
<div class="seo-tab-pane" id="tab-robots">
|
||
</form>{{-- ana form burada biter --}}
|
||
<div class="row g-4">
|
||
<div class="col-lg-7">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-robot"></i><h6>robots.txt Düzenle</h6></div>
|
||
<div class="section-card-body">
|
||
<form method="POST" action="{{ route('admin.seo.robots') }}">
|
||
@csrf
|
||
<textarea name="robots_txt" class="form-control robots-editor">{{ $robotsTxt ?: "User-agent: *\nDisallow: /admin\nDisallow: /api\nDisallow: /storage\n\nSitemap: https://animexe.com/sitemap.xml" }}</textarea>
|
||
<div class="mt-3 d-flex gap-2">
|
||
<button type="submit" class="btn btn-primary"><i class="bi bi-save me-1"></i>Kaydet</button>
|
||
<button type="button" class="btn btn-outline-secondary" onclick="resetRobots()"><i class="bi bi-arrow-counterclockwise me-1"></i>Sıfırla</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-lg-5">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-info-circle text-info"></i><h6>robots.txt Rehberi</h6></div>
|
||
<div class="section-card-body">
|
||
@foreach([
|
||
['Disallow: /admin','Admin panelini tara engelleyin. Güvenlik ve bant genişliği.'],
|
||
['Disallow: /api','API rotaları indexlenmemeli.'],
|
||
['Allow: /','Her şeye izin ver (varsayılan).'],
|
||
['Sitemap: https://...','Sitemap konumunu belirtin. Mecburi değil ama önerilir.'],
|
||
['User-agent: Googlebot','Sadece Google botu için kural yazın.'],
|
||
['Crawl-delay: 5','Bot tarama hızını saniye cinsinden sınırlayın.'],
|
||
] as $r)
|
||
<div class="mb-2" style="font-size:.8rem">
|
||
<code style="color:var(--info)">{{ $r[0] }}</code>
|
||
<div style="color:var(--text2);font-size:.73rem">{{ $r[1] }}</div>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<form method="POST" action="{{ route('admin.seo.update') }}" style="display:none" id="seo-reopen-form">@csrf</form>
|
||
|
||
{{-- ═══════ TAB 8: YÖNLENDİRMELER ═══════ --}}
|
||
</div>
|
||
<div class="seo-tab-pane" id="tab-redirects">
|
||
<div class="row g-4">
|
||
<div class="col-lg-4">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-plus-circle text-success"></i><h6>Yeni Yönlendirme Ekle</h6></div>
|
||
<div class="section-card-body">
|
||
<form method="POST" action="{{ route('admin.seo.redirects.store') }}">
|
||
@csrf
|
||
<div class="mb-3">
|
||
<label class="form-label">Kaynak URL <span class="text-danger">*</span></label>
|
||
<input type="text" name="from_path" class="form-control" placeholder="/eski-anime-sayfasi" required>
|
||
<div class="seo-field-help">Tam yol girin (/ile başlayan)</div>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">Hedef URL <span class="text-danger">*</span></label>
|
||
<input type="text" name="to_path" class="form-control" placeholder="/anime/naruto" required>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">Tür</label>
|
||
<select name="type" class="form-select">
|
||
<option value="301">301 — Kalıcı (SEO değerini devreder)</option>
|
||
<option value="302">302 — Geçici</option>
|
||
</select>
|
||
</div>
|
||
<button type="submit" class="btn btn-success w-100"><i class="bi bi-plus me-1"></i>Ekle</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-lg-8">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-table"></i><h6>Aktif Yönlendirmeler ({{ $redirects->total() }})</h6></div>
|
||
@if($redirects->isEmpty())
|
||
<div class="section-card-body text-center text-muted py-5">
|
||
<i class="bi bi-signpost-split" style="font-size:2rem;opacity:.3;display:block;margin-bottom:8px"></i>
|
||
Henüz yönlendirme eklenmedi.
|
||
</div>
|
||
@else
|
||
<div class="table-responsive">
|
||
<table class="table table-sm mb-0">
|
||
<thead class="table-dark">
|
||
<tr><th>Kaynak</th><th>Hedef</th><th style="width:60px">Tür</th><th style="width:70px">İsabet</th><th style="width:100px">Durum</th><th style="width:50px"></th></tr>
|
||
</thead>
|
||
<tbody>
|
||
@foreach($redirects as $rd)
|
||
<tr class="redirect-row {{ $rd->is_active?'':'inactive' }}">
|
||
<td><code style="font-size:.75rem;color:var(--info)">{{ $rd->from_path }}</code></td>
|
||
<td><code style="font-size:.75rem;color:var(--info)">{{ Str::limit($rd->to_path,40) }}</code></td>
|
||
<td><span class="badge {{ $rd->type===301?'bg-success':'bg-warning text-dark' }}" style="font-size:.7rem">{{ $rd->type }}</span></td>
|
||
<td><span class="text-muted" style="font-size:.8rem">{{ number_format($rd->hits) }}</span></td>
|
||
<td>
|
||
<button type="button" class="btn btn-sm {{ $rd->is_active?'btn-success':'btn-secondary' }} btn-toggle-redirect" data-id="{{ $rd->id }}" style="font-size:.72rem;padding:2px 8px">
|
||
{{ $rd->is_active?'Aktif':'Pasif' }}
|
||
</button>
|
||
</td>
|
||
<td>
|
||
<form method="POST" action="{{ route('admin.seo.redirects.destroy', $rd) }}" onsubmit="return confirm('Sil?')">
|
||
@csrf @method('DELETE')
|
||
<button class="btn btn-sm btn-outline-danger p-1"><i class="bi bi-trash" style="font-size:.75rem"></i></button>
|
||
</form>
|
||
</td>
|
||
</tr>
|
||
@endforeach
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="p-3 border-top border-secondary">{{ $redirects->links() }}</div>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ═══════ TAB 9: ANALİTİK & ARAÇLAR ═══════ --}}
|
||
<div class="seo-tab-pane" id="tab-google">
|
||
|
||
{{-- ── Integration Status Banner ─────────────────────────────────────── --}}
|
||
<div class="analytics-status-bar mb-4">
|
||
<div class="asb-label"><i class="bi bi-plug-fill me-1"></i>Entegrasyon Durumu</div>
|
||
<div class="asb-items">
|
||
<div class="asb-item {{ $integrations['ga4'] ? 'connected' : 'disconnected' }}">
|
||
<span class="asb-dot"></span>
|
||
<span class="asb-name">Google Analytics 4</span>
|
||
<span class="asb-tag">{{ $integrations['ga4'] ? ($settings['seo_google_analytics']??'') : 'Bağlı değil' }}</span>
|
||
</div>
|
||
<div class="asb-item {{ $integrations['gtm'] ? 'connected' : 'disconnected' }}">
|
||
<span class="asb-dot"></span>
|
||
<span class="asb-name">Tag Manager</span>
|
||
<span class="asb-tag">{{ $integrations['gtm'] ? ($settings['seo_gtm_id']??'') : 'Bağlı değil' }}</span>
|
||
</div>
|
||
<div class="asb-item {{ $integrations['gsc'] ? 'connected' : 'disconnected' }}">
|
||
<span class="asb-dot"></span>
|
||
<span class="asb-name">Search Console</span>
|
||
<span class="asb-tag">{{ $integrations['gsc'] ? 'Doğrulandı' : 'Bağlı değil' }}</span>
|
||
</div>
|
||
<div class="asb-item {{ $integrations['bing'] ? 'connected' : 'disconnected' }}">
|
||
<span class="asb-dot"></span>
|
||
<span class="asb-name">Bing Webmaster</span>
|
||
<span class="asb-tag">{{ $integrations['bing'] ? 'Doğrulandı' : 'Bağlı değil' }}</span>
|
||
</div>
|
||
<div class="asb-item {{ $integrations['yandex'] ? 'connected' : 'disconnected' }}">
|
||
<span class="asb-dot"></span>
|
||
<span class="asb-name">Yandex</span>
|
||
<span class="asb-tag">{{ $integrations['yandex'] ? 'Doğrulandı' : 'Bağlı değil' }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ── KPI Cards Row ─────────────────────────────────────────────────── --}}
|
||
<div class="row g-3 mb-4">
|
||
<div class="col-6 col-md-3 col-xl">
|
||
<div class="analytics-kpi-card">
|
||
<div class="kpi-icon" style="background:rgba(88,166,255,.12);color:var(--info)"><i class="bi bi-film"></i></div>
|
||
<div class="kpi-body">
|
||
<div class="kpi-val">{{ number_format($analyticsStats['total_anime']) }}</div>
|
||
<div class="kpi-lbl">Toplam Anime</div>
|
||
@if($analyticsStats['new_anime_this_month'] > 0)
|
||
<div class="kpi-trend up"><i class="bi bi-arrow-up-short"></i>+{{ $analyticsStats['new_anime_this_month'] }} bu ay</div>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-6 col-md-3 col-xl">
|
||
<div class="analytics-kpi-card">
|
||
<div class="kpi-icon" style="background:rgba(63,185,80,.12);color:var(--success)"><i class="bi bi-people-fill"></i></div>
|
||
<div class="kpi-body">
|
||
<div class="kpi-val">{{ number_format($analyticsStats['total_users']) }}</div>
|
||
<div class="kpi-lbl">Toplam Üye</div>
|
||
@if($analyticsStats['new_users_this_month'] > 0)
|
||
<div class="kpi-trend up"><i class="bi bi-arrow-up-short"></i>+{{ $analyticsStats['new_users_this_month'] }} bu ay</div>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-6 col-md-3 col-xl">
|
||
<div class="analytics-kpi-card">
|
||
<div class="kpi-icon" style="background:rgba(210,153,34,.12);color:#d29922"><i class="bi bi-collection-play-fill"></i></div>
|
||
<div class="kpi-body">
|
||
<div class="kpi-val">{{ number_format($analyticsStats['total_episodes']) }}</div>
|
||
<div class="kpi-lbl">Toplam Bölüm</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-6 col-md-3 col-xl">
|
||
<div class="analytics-kpi-card">
|
||
<div class="kpi-icon" style="background:rgba(240,81,51,.12);color:#f05133"><i class="bi bi-chat-dots-fill"></i></div>
|
||
<div class="kpi-body">
|
||
<div class="kpi-val">{{ number_format($analyticsStats['total_comments']) }}</div>
|
||
<div class="kpi-lbl">Toplam Yorum</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-6 col-md-3 col-xl">
|
||
<div class="analytics-kpi-card">
|
||
<div class="kpi-icon" style="background:rgba(163,113,247,.12);color:#a371f7"><i class="bi bi-bookmark-heart-fill"></i></div>
|
||
<div class="kpi-body">
|
||
<div class="kpi-val">{{ number_format($analyticsStats['total_watchlists']) }}</div>
|
||
<div class="kpi-lbl">İzleme Listesi</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-6 col-md-3 col-xl">
|
||
<div class="analytics-kpi-card">
|
||
<div class="kpi-icon" style="background:rgba(255,107,53,.12);color:#ff6b35"><i class="bi bi-star-fill"></i></div>
|
||
<div class="kpi-body">
|
||
<div class="kpi-val">{{ number_format($analyticsStats['total_ratings']) }}</div>
|
||
<div class="kpi-lbl">Toplam Rating</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ── SEO Coverage + Redirect Stats ───────────────────────────────────── --}}
|
||
<div class="row g-3 mb-4">
|
||
<div class="col-lg-8">
|
||
<div class="section-card h-100">
|
||
<div class="section-card-header"><i class="bi bi-graph-up-arrow text-success me-1"></i><h6>SEO Kapsama & Sağlık Skoru</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="row g-4">
|
||
<div class="col-md-4 text-center">
|
||
@php
|
||
$overallScore = round(($analyticsStats['seo_title_pct'] + $analyticsStats['seo_desc_pct']) / 2);
|
||
$scoreColor = $overallScore >= 80 ? 'var(--success)' : ($overallScore >= 50 ? '#d29922' : 'var(--danger)');
|
||
$circumference = 2 * pi() * 52;
|
||
$dashOffset = $circumference * (1 - $overallScore / 100);
|
||
@endphp
|
||
<div class="seo-score-ring" style="width:130px;height:130px">
|
||
<svg width="130" height="130" viewBox="0 0 130 130">
|
||
<circle cx="65" cy="65" r="52" fill="none" stroke="var(--border)" stroke-width="10"/>
|
||
<circle cx="65" cy="65" r="52" fill="none" stroke="{{ $scoreColor }}" stroke-width="10"
|
||
stroke-dasharray="{{ $circumference }}"
|
||
stroke-dashoffset="{{ $dashOffset }}"
|
||
stroke-linecap="round"/>
|
||
</svg>
|
||
<div class="score-text">
|
||
<div class="score-num" style="color:{{ $scoreColor }}">{{ $overallScore }}</div>
|
||
<div class="score-lbl">SEO Skoru</div>
|
||
</div>
|
||
</div>
|
||
<div class="mt-2" style="font-size:.78rem;color:var(--text2)">{{ $analyticsStats['total_anime'] }} anime üzerinden</div>
|
||
</div>
|
||
<div class="col-md-8">
|
||
<div class="mb-3">
|
||
<div class="d-flex justify-content-between mb-1" style="font-size:.82rem">
|
||
<span>SEO Başlık Kapsama</span>
|
||
<span class="fw-bold" style="color:{{ $analyticsStats['seo_title_pct'] >= 80 ? 'var(--success)' : '#d29922' }}">{{ $analyticsStats['seo_title_pct'] }}%</span>
|
||
</div>
|
||
<div class="seo-coverage-bar">
|
||
<div class="seo-coverage-fill" style="width:{{ $analyticsStats['seo_title_pct'] }}%"></div>
|
||
</div>
|
||
<div style="font-size:.73rem;color:var(--text2);margin-top:3px">{{ $animeSeoCoverage['has_seo_title'] }} / {{ $animeSeoCoverage['total'] }} anime</div>
|
||
</div>
|
||
<div class="mb-3">
|
||
<div class="d-flex justify-content-between mb-1" style="font-size:.82rem">
|
||
<span>SEO Açıklama Kapsama</span>
|
||
<span class="fw-bold" style="color:{{ $analyticsStats['seo_desc_pct'] >= 80 ? 'var(--success)' : '#d29922' }}">{{ $analyticsStats['seo_desc_pct'] }}%</span>
|
||
</div>
|
||
<div class="seo-coverage-bar">
|
||
<div class="seo-coverage-fill" style="width:{{ $analyticsStats['seo_desc_pct'] }}%"></div>
|
||
</div>
|
||
<div style="font-size:.73rem;color:var(--text2);margin-top:3px">{{ $animeSeoCoverage['has_seo_desc'] }} / {{ $animeSeoCoverage['total'] }} anime</div>
|
||
</div>
|
||
<div class="row g-2 mt-2">
|
||
<div class="col-6">
|
||
<div class="analytics-mini-stat">
|
||
<div class="ams-val" style="color:var(--info)">{{ $analyticsStats['total_genres'] }}</div>
|
||
<div class="ams-lbl">Aktif Tür</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-6">
|
||
<div class="analytics-mini-stat">
|
||
<div class="ams-val" style="color:#a371f7">{{ $analyticsStats['total_blog_posts'] }}</div>
|
||
<div class="ams-lbl">Blog Yazısı</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-lg-4">
|
||
<div class="section-card h-100">
|
||
<div class="section-card-header"><i class="bi bi-signpost-split text-info me-1"></i><h6>Yönlendirme İstatistikleri</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="redirect-stat-grid">
|
||
<div class="rsg-item">
|
||
<div class="rsg-val" style="color:var(--info)">{{ $analyticsStats['total_redirects'] }}</div>
|
||
<div class="rsg-lbl">Aktif Yönlendirme</div>
|
||
</div>
|
||
<div class="rsg-item">
|
||
<div class="rsg-val" style="color:var(--success)">{{ number_format($analyticsStats['total_redirect_hits']) }}</div>
|
||
<div class="rsg-lbl">Toplam Tıklama</div>
|
||
</div>
|
||
</div>
|
||
<hr style="border-color:var(--border)">
|
||
<div style="font-size:.82rem;color:var(--text2);line-height:1.8">
|
||
<div><i class="bi bi-check-circle-fill text-success me-1"></i>301 Kalıcı yönlendirmeler SEO güçlendirir</div>
|
||
<div><i class="bi bi-exclamation-triangle-fill text-warning me-1"></i>302 Geçici yönlendirmeler juice aktarmaz</div>
|
||
<div><i class="bi bi-info-circle-fill text-info me-1"></i>Redirect zinciri oluşturmaktan kaçının</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ── Quick Tool Links ─────────────────────────────────────────────────── --}}
|
||
<div class="section-card mb-4">
|
||
<div class="section-card-header"><i class="bi bi-grid-3x3-gap-fill me-1"></i><h6>Hızlı Araç Erişimi</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="quick-tools-grid">
|
||
<a href="https://analytics.google.com" target="_blank" class="qt-card">
|
||
<div class="qt-icon" style="background:#e37400;color:#fff"><i class="bi bi-bar-chart-line-fill"></i></div>
|
||
<div class="qt-body">
|
||
<div class="qt-name">Google Analytics 4</div>
|
||
<div class="qt-desc">Trafik, kullanıcı davranışı, dönüşümler</div>
|
||
</div>
|
||
<div class="qt-status {{ $integrations['ga4'] ? 'on' : 'off' }}">{{ $integrations['ga4'] ? 'Aktif' : 'Kurulmadı' }}</div>
|
||
</a>
|
||
<a href="https://search.google.com/search-console" target="_blank" class="qt-card">
|
||
<div class="qt-icon" style="background:#4285f4;color:#fff"><i class="bi bi-search"></i></div>
|
||
<div class="qt-body">
|
||
<div class="qt-name">Search Console</div>
|
||
<div class="qt-desc">Arama sıralamaları, tıklamalar, hatalar</div>
|
||
</div>
|
||
<div class="qt-status {{ $integrations['gsc'] ? 'on' : 'off' }}">{{ $integrations['gsc'] ? 'Doğrulandı' : 'Doğrulanmadı' }}</div>
|
||
</a>
|
||
<a href="https://tagmanager.google.com" target="_blank" class="qt-card">
|
||
<div class="qt-icon" style="background:#346beb;color:#fff"><i class="bi bi-tags-fill"></i></div>
|
||
<div class="qt-body">
|
||
<div class="qt-name">Tag Manager</div>
|
||
<div class="qt-desc">Kod snippet yönetimi, etkinlikler</div>
|
||
</div>
|
||
<div class="qt-status {{ $integrations['gtm'] ? 'on' : 'off' }}">{{ $integrations['gtm'] ? 'Aktif' : 'Kurulmadı' }}</div>
|
||
</a>
|
||
<a href="https://www.bing.com/webmasters" target="_blank" class="qt-card">
|
||
<div class="qt-icon" style="background:#008373;color:#fff"><i class="bi bi-microsoft"></i></div>
|
||
<div class="qt-body">
|
||
<div class="qt-name">Bing Webmaster</div>
|
||
<div class="qt-desc">Bing arama görünürlüğü ve indexleme</div>
|
||
</div>
|
||
<div class="qt-status {{ $integrations['bing'] ? 'on' : 'off' }}">{{ $integrations['bing'] ? 'Doğrulandı' : 'Doğrulanmadı' }}</div>
|
||
</a>
|
||
<a href="https://webmaster.yandex.com" target="_blank" class="qt-card">
|
||
<div class="qt-icon" style="background:#fc3f1d;color:#fff"><i class="bi bi-globe"></i></div>
|
||
<div class="qt-body">
|
||
<div class="qt-name">Yandex Webmaster</div>
|
||
<div class="qt-desc">Yandex arama indexleme ve istatistikleri</div>
|
||
</div>
|
||
<div class="qt-status {{ $integrations['yandex'] ? 'on' : 'off' }}">{{ $integrations['yandex'] ? 'Doğrulandı' : 'Doğrulanmadı' }}</div>
|
||
</a>
|
||
<a href="https://pagespeed.web.dev" target="_blank" class="qt-card">
|
||
<div class="qt-icon" style="background:#34a853;color:#fff"><i class="bi bi-speedometer2"></i></div>
|
||
<div class="qt-body">
|
||
<div class="qt-name">PageSpeed Insights</div>
|
||
<div class="qt-desc">Core Web Vitals ve performans testi</div>
|
||
</div>
|
||
<div class="qt-status off">Web Aracı</div>
|
||
</a>
|
||
<a href="https://schema.org/docs/gs.html" target="_blank" class="qt-card">
|
||
<div class="qt-icon" style="background:#5f6368;color:#fff"><i class="bi bi-braces-asterisk"></i></div>
|
||
<div class="qt-body">
|
||
<div class="qt-name">Schema.org Validator</div>
|
||
<div class="qt-desc">Yapısal veri test ve doğrulama aracı</div>
|
||
</div>
|
||
<div class="qt-status off">Dış Araç</div>
|
||
</a>
|
||
<a href="https://ahrefs.com/backlink-checker" target="_blank" class="qt-card">
|
||
<div class="qt-icon" style="background:#1f7ae0;color:#fff"><i class="bi bi-link-45deg"></i></div>
|
||
<div class="qt-body">
|
||
<div class="qt-name">Ahrefs Backlink</div>
|
||
<div class="qt-desc">Geri bağlantı analizi ve rakip araştırma</div>
|
||
</div>
|
||
<div class="qt-status off">Dış Araç</div>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ── Embed Dashboard ─────────────────────────────────────────────────── --}}
|
||
<div class="section-card mb-4">
|
||
<div class="section-card-header">
|
||
<i class="bi bi-easel2 text-warning me-1"></i><h6>Gömülü Rapor Paneli (Looker Studio)</h6>
|
||
<span class="ms-auto" style="font-size:.75rem;color:var(--text2)">Looker Studio embed URL'sini girin</span>
|
||
</div>
|
||
<div class="section-card-body">
|
||
<div class="row g-3 align-items-end mb-3">
|
||
<div class="col">
|
||
<input type="text" id="embedUrl" class="form-control" placeholder="https://lookerstudio.google.com/embed/reporting/xxx/page/xxx" value="{{ $settings['seo_looker_embed_url'] ?? '' }}">
|
||
<div class="seo-field-help">Looker Studio → Dosya → Raporu göm → URL kopyala</div>
|
||
</div>
|
||
<div class="col-auto">
|
||
<button class="btn btn-outline-primary" onclick="loadEmbed()"><i class="bi bi-play-fill me-1"></i>Yükle</button>
|
||
<button class="btn btn-outline-secondary ms-1" onclick="saveEmbedUrl()"><i class="bi bi-save me-1"></i>Kaydet</button>
|
||
</div>
|
||
</div>
|
||
<div id="embedContainer" style="border-radius:10px;overflow:hidden;background:#010409;border:1px solid var(--border);min-height:160px;display:flex;align-items:center;justify-content:center">
|
||
@if(!empty($settings['seo_looker_embed_url'] ?? ''))
|
||
<iframe id="embedFrame" src="{{ $settings['seo_looker_embed_url'] }}"
|
||
style="width:100%;height:600px;border:0" allowfullscreen></iframe>
|
||
@else
|
||
<div id="embedPlaceholder" class="text-center py-5 text-muted">
|
||
<i class="bi bi-easel2" style="font-size:3rem;display:block;margin-bottom:12px;opacity:.3"></i>
|
||
<div style="font-size:.88rem">Looker Studio URL giriniz ve <strong>Yükle</strong>'ye tıklayın</div>
|
||
<div style="font-size:.78rem;margin-top:6px">Ya da doğrudan GA4 Analytics panelini kullanın</div>
|
||
<a href="https://analytics.google.com" target="_blank" class="btn btn-sm btn-outline-primary mt-3">
|
||
<i class="bi bi-box-arrow-up-right me-1"></i>Google Analytics'i Aç
|
||
</a>
|
||
</div>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ── Settings Form ─────────────────────────────────────────────────── --}}
|
||
<form method="POST" action="{{ route('admin.seo.update') }}">
|
||
@csrf
|
||
<div class="row g-4">
|
||
<div class="col-lg-6">
|
||
<div class="section-card">
|
||
<div class="section-card-header">
|
||
<i class="bi bi-bar-chart-line text-warning me-1"></i><h6>Tracking Kodları</h6>
|
||
</div>
|
||
<div class="section-card-body">
|
||
<div class="mb-4">
|
||
<div class="d-flex align-items-center justify-content-between mb-1">
|
||
<label class="form-label mb-0">Google Analytics 4 (Measurement ID)</label>
|
||
@if($integrations['ga4'])
|
||
<span class="badge" style="background:rgba(63,185,80,.15);color:var(--success);font-size:.7rem">
|
||
<i class="bi bi-check-circle me-1"></i>Aktif
|
||
</span>
|
||
@else
|
||
<span class="badge" style="background:rgba(248,81,73,.1);color:var(--danger);font-size:.7rem">
|
||
<i class="bi bi-x-circle me-1"></i>Kurulmadı
|
||
</span>
|
||
@endif
|
||
</div>
|
||
<div class="input-group">
|
||
<span class="input-group-text" style="background:var(--surface);border-color:var(--border2);color:var(--text2)">
|
||
<i class="bi bi-bar-chart-line"></i>
|
||
</span>
|
||
<input type="text" name="seo_google_analytics" class="form-control" value="{{ $settings['seo_google_analytics']??'' }}" placeholder="G-XXXXXXXXXX">
|
||
</div>
|
||
<div class="seo-field-help">GA4 ölçüm kimliği. <head> içine otomatik eklenir.</div>
|
||
</div>
|
||
<div class="mb-4">
|
||
<div class="d-flex align-items-center justify-content-between mb-1">
|
||
<label class="form-label mb-0">Google Tag Manager</label>
|
||
@if($integrations['gtm'])
|
||
<span class="badge" style="background:rgba(63,185,80,.15);color:var(--success);font-size:.7rem">
|
||
<i class="bi bi-check-circle me-1"></i>Aktif
|
||
</span>
|
||
@else
|
||
<span class="badge" style="background:rgba(139,148,158,.1);color:var(--text2);font-size:.7rem">
|
||
<i class="bi bi-dash-circle me-1"></i>Opsiyonel
|
||
</span>
|
||
@endif
|
||
</div>
|
||
<div class="input-group">
|
||
<span class="input-group-text" style="background:var(--surface);border-color:var(--border2);color:var(--text2)">
|
||
<i class="bi bi-tags-fill"></i>
|
||
</span>
|
||
<input type="text" name="seo_gtm_id" class="form-control" value="{{ $settings['seo_gtm_id']??'' }}" placeholder="GTM-XXXXXXX">
|
||
</div>
|
||
<div class="seo-field-help">GA4 ile birlikte kullanılabilir veya alternatif olarak.</div>
|
||
</div>
|
||
<div>
|
||
<label class="form-label">Looker Studio Embed URL</label>
|
||
<div class="input-group">
|
||
<span class="input-group-text" style="background:var(--surface);border-color:var(--border2);color:var(--text2)">
|
||
<i class="bi bi-easel2"></i>
|
||
</span>
|
||
<input type="text" name="seo_looker_embed_url" class="form-control" value="{{ $settings['seo_looker_embed_url']??'' }}" placeholder="https://lookerstudio.google.com/embed/...">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-lg-6">
|
||
<div class="section-card">
|
||
<div class="section-card-header">
|
||
<i class="bi bi-patch-check text-success me-1"></i><h6>Webmaster Doğrulama Kodları</h6>
|
||
</div>
|
||
<div class="section-card-body">
|
||
<div class="mb-3">
|
||
<div class="d-flex align-items-center justify-content-between mb-1">
|
||
<label class="form-label mb-0">Google Search Console</label>
|
||
@if($integrations['gsc'])
|
||
<span class="badge" style="background:rgba(63,185,80,.15);color:var(--success);font-size:.7rem"><i class="bi bi-check-circle me-1"></i>Doğrulandı</span>
|
||
@else
|
||
<span class="badge" style="background:rgba(248,81,73,.1);color:var(--danger);font-size:.7rem"><i class="bi bi-exclamation-circle me-1"></i>Doğrulanmadı</span>
|
||
@endif
|
||
</div>
|
||
<div class="input-group">
|
||
<span class="input-group-text" style="background:var(--surface);border-color:var(--border2);color:#4285f4"><i class="bi bi-google"></i></span>
|
||
<input type="text" name="seo_gsc_verification" class="form-control" value="{{ $settings['seo_gsc_verification']??'' }}" placeholder="google-site-verification=abc123">
|
||
</div>
|
||
<div class="seo-field-help">Search Console → Ayarlar → Site doğrulama → HTML etiketi yöntemi</div>
|
||
</div>
|
||
<div class="mb-3">
|
||
<div class="d-flex align-items-center justify-content-between mb-1">
|
||
<label class="form-label mb-0">Bing Webmaster</label>
|
||
@if($integrations['bing'])
|
||
<span class="badge" style="background:rgba(63,185,80,.15);color:var(--success);font-size:.7rem"><i class="bi bi-check-circle me-1"></i>Doğrulandı</span>
|
||
@else
|
||
<span class="badge" style="background:rgba(139,148,158,.1);color:var(--text2);font-size:.7rem"><i class="bi bi-dash-circle me-1"></i>Kurulmadı</span>
|
||
@endif
|
||
</div>
|
||
<div class="input-group">
|
||
<span class="input-group-text" style="background:var(--surface);border-color:var(--border2);color:#008373"><i class="bi bi-microsoft"></i></span>
|
||
<input type="text" name="seo_bing_verification" class="form-control" value="{{ $settings['seo_bing_verification']??'' }}" placeholder="msvalidate.01 içeriği">
|
||
</div>
|
||
</div>
|
||
<div class="mb-4">
|
||
<div class="d-flex align-items-center justify-content-between mb-1">
|
||
<label class="form-label mb-0">Yandex Webmaster</label>
|
||
@if($integrations['yandex'])
|
||
<span class="badge" style="background:rgba(63,185,80,.15);color:var(--success);font-size:.7rem"><i class="bi bi-check-circle me-1"></i>Doğrulandı</span>
|
||
@else
|
||
<span class="badge" style="background:rgba(139,148,158,.1);color:var(--text2);font-size:.7rem"><i class="bi bi-dash-circle me-1"></i>Kurulmadı</span>
|
||
@endif
|
||
</div>
|
||
<div class="input-group">
|
||
<span class="input-group-text" style="background:var(--surface);border-color:var(--border2);color:#fc3f1d"><i class="bi bi-globe"></i></span>
|
||
<input type="text" name="seo_yandex_verification" class="form-control" value="{{ $settings['seo_yandex_verification']??'' }}" placeholder="yandex-verification içeriği">
|
||
</div>
|
||
</div>
|
||
{{-- GSC Setup Guide --}}
|
||
<div class="gsc-guide-box">
|
||
<div class="ggb-title"><i class="bi bi-lightbulb-fill text-warning me-1"></i>Search Console Kurulum Adımları</div>
|
||
<ol class="ggb-steps">
|
||
<li><a href="https://search.google.com/search-console" target="_blank">Search Console</a>'u açın ve sitenizi ekleyin</li>
|
||
<li>"HTML etiketi" doğrulama yöntemini seçin</li>
|
||
<li>Verification içeriğini buraya yapıştırın ve kaydedin</li>
|
||
<li>Search Console'a dönüp "Doğrula" butonuna basın</li>
|
||
<li>Sitemap gönderin: <code>{{ config('app.url') }}/sitemap.xml</code></li>
|
||
</ol>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="d-flex gap-2 mt-2">
|
||
<button type="submit" class="btn btn-primary px-4"><i class="bi bi-save me-2"></i>Entegrasyon Ayarlarını Kaydet</button>
|
||
@if($integrations['ga4'])
|
||
<a href="https://analytics.google.com" target="_blank" class="btn btn-outline-warning">
|
||
<i class="bi bi-box-arrow-up-right me-1"></i>GA4'ü Aç
|
||
</a>
|
||
@endif
|
||
@if($integrations['gsc'])
|
||
<a href="https://search.google.com/search-console" target="_blank" class="btn btn-outline-primary">
|
||
<i class="bi bi-search me-1"></i>Search Console'u Aç
|
||
</a>
|
||
@endif
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
{{-- ═══════ TAB 10: PAGESPEED ═══════ --}}
|
||
<div class="seo-tab-pane" id="tab-pagespeed">
|
||
<div class="row g-4">
|
||
<div class="col-lg-5">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-speedometer2"></i><h6>PageSpeed Insights Testi</h6></div>
|
||
<div class="section-card-body">
|
||
<form method="POST" action="{{ route('admin.seo.update') }}" class="mb-3">
|
||
@csrf
|
||
<label class="form-label">PageSpeed API Anahtarı</label>
|
||
<div class="input-group mb-1">
|
||
<input type="text" name="seo_pagespeed_api_key" class="form-control" value="{{ $settings['seo_pagespeed_api_key']??'' }}" placeholder="AIzaSy...">
|
||
<button type="submit" class="btn btn-outline-secondary">Kaydet</button>
|
||
</div>
|
||
<div class="seo-field-help">Google Cloud Console'dan API anahtarı alın. PageSpeed Insights API'yi etkinleştirin.</div>
|
||
</form>
|
||
|
||
<hr style="border-color:var(--border)">
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label">Test Edilecek URL</label>
|
||
<input type="url" id="psi-url" class="form-control" value="{{ $settings['seo_canonical_domain']??'' }}" placeholder="https://animexe.com">
|
||
</div>
|
||
<div class="mb-3">
|
||
<label class="form-label">Cihaz</label>
|
||
<div class="d-flex gap-2">
|
||
<button type="button" class="btn btn-outline-secondary btn-sm psi-strat active" data-strat="mobile"><i class="bi bi-phone me-1"></i>Mobil</button>
|
||
<button type="button" class="btn btn-outline-secondary btn-sm psi-strat" data-strat="desktop"><i class="bi bi-laptop me-1"></i>Masaüstü</button>
|
||
</div>
|
||
</div>
|
||
<button type="button" id="btn-psi-run" class="btn btn-primary w-100">
|
||
<i class="bi bi-play-circle me-1"></i>Testi Çalıştır
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-lg-7">
|
||
<div id="psi-results" style="display:none">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-bar-chart me-1"></i><h6>Sonuçlar</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="d-flex justify-content-around mb-4" id="psi-scores"></div>
|
||
<div class="row g-2 mb-3" id="psi-vitals"></div>
|
||
<div id="psi-opportunities"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="psi-loading" style="display:none" class="text-center py-5">
|
||
<div class="spinner-border text-info" style="width:3rem;height:3rem"></div>
|
||
<div class="mt-3 text-muted">PageSpeed analiz ediliyor... (10–20 saniye)</div>
|
||
</div>
|
||
<div id="psi-placeholder" class="section-card">
|
||
<div class="section-card-body text-center py-5 text-muted">
|
||
<i class="bi bi-speedometer2" style="font-size:3rem;opacity:.2;display:block;margin-bottom:12px"></i>
|
||
<div>API anahtarınızı girin ve test başlatın.</div>
|
||
<div style="font-size:.78rem;margin-top:4px">Core Web Vitals, skor ve optimizasyon önerileri gösterilecek.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ═══════ TAB 11: DENETİM ═══════ --}}
|
||
<div class="seo-tab-pane" id="tab-audit">
|
||
<div class="row g-4">
|
||
<div class="col-lg-6">
|
||
<div class="section-card">
|
||
<div class="section-card-header d-flex align-items-center justify-content-between">
|
||
<div class="d-flex align-items-center gap-2"><i class="bi bi-clipboard-check"></i><h6 class="mb-0">SEO Kontrol Listesi ({{ count($audit['checks']) }} kontrol)</h6></div>
|
||
<button type="button" class="btn btn-sm btn-outline-info" id="btn-reaudit"><i class="bi bi-arrow-clockwise me-1"></i>Yenile</button>
|
||
</div>
|
||
<div class="section-card-body">
|
||
@foreach($audit['checks'] as $c)
|
||
<div class="check-item {{ $c['pass']?'pass':'fail' }}">
|
||
<span class="check-icon"><i class="bi bi-{{ $c['pass']?'check-circle-fill':'x-circle-fill' }}"></i></span>
|
||
<span class="check-msg">{{ $c['pass']?$c['passMsg']:$c['failMsg'] }}</span>
|
||
<span class="check-weight">+{{ $c['weight'] }}p</span>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="col-lg-6">
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-copy text-warning"></i><h6>Yinelenen İçerik Denetimi</h6></div>
|
||
<div class="section-card-body">
|
||
@if($dupDesc > 0)
|
||
<div class="alert alert-warning d-flex align-items-center gap-2">
|
||
<i class="bi bi-exclamation-triangle-fill"></i>
|
||
<span><strong>{{ $dupDesc }} grup</strong> tekrarlayan anime açıklaması tespit edildi.</span>
|
||
</div>
|
||
@else
|
||
<div class="alert alert-success d-flex align-items-center gap-2">
|
||
<i class="bi bi-check-circle-fill"></i>Tekrarlayan içerik tespit edilmedi.
|
||
</div>
|
||
@endif
|
||
<button type="button" id="btn-dup-check" class="btn btn-outline-warning w-100">
|
||
<i class="bi bi-search me-1"></i>Tekrarlayan İçerikleri Listele
|
||
</button>
|
||
<div id="dup-results" class="mt-3" style="display:none"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-link-45deg text-info"></i><h6>Dahili Bağlantı Analizi</h6></div>
|
||
<div class="section-card-body">
|
||
<p class="text-muted" style="font-size:.82rem">Hangi animeler diğer animelerin açıklamalarında hiç atıflanmıyor? (Orphaned pages)</p>
|
||
<button type="button" id="btn-internal-links" class="btn btn-outline-info w-100">
|
||
<i class="bi bi-diagram-2 me-1"></i>Dahili Bağlantı Analizini Çalıştır
|
||
</button>
|
||
<div id="link-loading" style="display:none" class="text-center mt-3 text-muted"><div class="spinner-border spinner-border-sm me-2"></div>Analiz ediliyor...</div>
|
||
<div id="link-results" class="mt-3" style="display:none;max-height:300px;overflow-y:auto"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section-card">
|
||
<div class="section-card-header"><i class="bi bi-stars text-success"></i><h6>Hızlı Aksiyon</h6></div>
|
||
<div class="section-card-body">
|
||
<div class="d-grid gap-2">
|
||
<button type="button" class="btn btn-outline-success" onclick="document.querySelector('[data-tab=anime-seo]').click()">
|
||
<i class="bi bi-collection-play me-1"></i>Anime SEO Başlıklarını Düzenle
|
||
</button>
|
||
<button type="button" class="btn btn-outline-info" onclick="document.querySelector('[data-tab=keywords]').click()">
|
||
<i class="bi bi-search me-1"></i>Anahtar Kelime Ekle
|
||
</button>
|
||
<button type="button" class="btn btn-outline-warning" onclick="document.querySelector('[data-tab=redirects]').click()">
|
||
<i class="bi bi-signpost-split me-1"></i>Yönlendirme Ekle
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ═══════ TAB 12: AI ASISTAN ═══════ --}}
|
||
<div class="seo-tab-pane" id="tab-ai">
|
||
|
||
@php $aiConfigured = !empty(\App\Models\Setting::get('deepseek_api_key','')); @endphp
|
||
|
||
@if(!$aiConfigured)
|
||
<div class="alert alert-warning d-flex align-items-center gap-3 mb-4">
|
||
<i class="bi bi-exclamation-triangle-fill" style="font-size:1.3rem"></i>
|
||
<div>
|
||
<strong>DeepSeek API Anahtarı Gerekli</strong><br>
|
||
<span style="font-size:.85rem">AI özelliklerini kullanmak için <a href="{{ route('admin.settings.index') }}" class="alert-link">Ayarlar</a> sayfasından DeepSeek API anahtarını ekleyin.</span>
|
||
</div>
|
||
</div>
|
||
@endif
|
||
|
||
<div class="row g-4">
|
||
|
||
{{-- Sol: Chat + Hızlı Araçlar --}}
|
||
<div class="col-lg-5">
|
||
|
||
{{-- AI Chat --}}
|
||
<div class="section-card" style="height:580px;display:flex;flex-direction:column">
|
||
<div class="section-card-header" style="flex-shrink:0">
|
||
<i class="bi bi-stars" style="color:var(--accent)"></i>
|
||
<h6>AI SEO Danışmanı</h6>
|
||
<span class="badge bg-success ms-auto" style="font-size:.68rem">DeepSeek</span>
|
||
</div>
|
||
<div id="ai-chat-messages" style="flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px">
|
||
<div class="ai-msg assistant">
|
||
<div class="ai-bubble">
|
||
<strong>Merhaba! Ben Animexe'nin AI SEO danışmanıyım.</strong><br><br>
|
||
Size şu konularda yardımcı olabilirim:<br>
|
||
• Anahtar kelime stratejisi<br>
|
||
• Meta başlık/açıklama optimizasyonu<br>
|
||
• Teknik SEO sorunları<br>
|
||
• İçerik stratejisi ve rakip analizi<br>
|
||
• Schema.org ve yapısal veri<br><br>
|
||
Ne öğrenmek istersiniz?
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div style="flex-shrink:0;padding:12px;border-top:1px solid var(--border)">
|
||
<div class="d-flex gap-2">
|
||
<textarea id="ai-chat-input" class="form-control form-control-sm" rows="2" placeholder="SEO sorunuzu yazın..." style="resize:none" {{ !$aiConfigured?'disabled':'' }}></textarea>
|
||
<button id="btn-ai-send" class="btn btn-primary" style="min-width:44px" {{ !$aiConfigured?'disabled':'' }}>
|
||
<i class="bi bi-send"></i>
|
||
</button>
|
||
</div>
|
||
<div class="d-flex gap-1 mt-2 flex-wrap" id="ai-quick-prompts">
|
||
@foreach(['Anahtar kelime stratejisi öner','Teknik SEO sorunlarım neler?','Rakip analizi yap','Core Web Vitals nedir?','Schema nasıl eklenir?'] as $qp)
|
||
<button type="button" class="btn btn-outline-secondary btn-quick-prompt" style="font-size:.7rem;padding:2px 8px" {{ !$aiConfigured?'disabled':'' }}>{{ $qp }}</button>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Sağ: AI Araçlar --}}
|
||
<div class="col-lg-7">
|
||
|
||
{{-- Anime AI SEO Üretici --}}
|
||
<div class="section-card">
|
||
<div class="section-card-header">
|
||
<i class="bi bi-collection-play" style="color:var(--accent)"></i>
|
||
<h6>AI Anime SEO Üretici</h6>
|
||
<span class="badge bg-info text-dark ms-auto" style="font-size:.68rem">Kaliteli / AI Destekli</span>
|
||
</div>
|
||
<div class="section-card-body">
|
||
<p style="font-size:.82rem;color:var(--text2)">Seçtiğiniz anime için DeepSeek AI gerçek anahtar kelime araştırması yaparak CTR-optimize edilmiş SEO başlığı ve meta açıklaması üretir.</p>
|
||
<div class="d-flex gap-2 mb-3">
|
||
<select id="ai-anime-select" class="form-select form-select-sm" {{ !$aiConfigured?'disabled':'' }}>
|
||
<option value="">— Anime seçin —</option>
|
||
@foreach(\App\Models\Anime::where('is_published',true)->orderBy('title')->get(['id','title','seo_title']) as $a)
|
||
<option value="{{ $a->id }}" data-has-seo="{{ $a->seo_title?1:0 }}">
|
||
{{ $a->title }}{{ $a->seo_title ? ' ✓' : '' }}
|
||
</option>
|
||
@endforeach
|
||
</select>
|
||
<button id="btn-ai-anime-gen" class="btn btn-primary btn-sm" style="white-space:nowrap" {{ !$aiConfigured?'disabled':'' }}>
|
||
<i class="bi bi-stars me-1"></i>AI ile Oluştur
|
||
</button>
|
||
</div>
|
||
<div id="ai-anime-result" style="display:none">
|
||
<div class="row g-2">
|
||
<div class="col-12">
|
||
<label style="font-size:.75rem;color:var(--text2)">SEO Başlığı</label>
|
||
<input type="text" id="ai-anime-title-out" class="form-control form-control-sm" readonly>
|
||
<div id="ai-anime-title-len" style="font-size:.7rem;text-align:right;color:var(--text2)"></div>
|
||
</div>
|
||
<div class="col-12">
|
||
<label style="font-size:.75rem;color:var(--text2)">Meta Açıklaması</label>
|
||
<textarea id="ai-anime-desc-out" class="form-control form-control-sm" rows="3" readonly></textarea>
|
||
<div id="ai-anime-desc-len" style="font-size:.7rem;text-align:right;color:var(--text2)"></div>
|
||
</div>
|
||
<div class="col-12">
|
||
<label style="font-size:.75rem;color:var(--text2)">Anahtar Kelimeler</label>
|
||
<input type="text" id="ai-anime-kw-out" class="form-control form-control-sm" readonly>
|
||
</div>
|
||
<div class="col-6">
|
||
<label style="font-size:.75rem;color:var(--text2)">Ana Kelime</label>
|
||
<input type="text" id="ai-anime-primary-kw" class="form-control form-control-sm" readonly>
|
||
</div>
|
||
<div class="col-6">
|
||
<label style="font-size:.75rem;color:var(--text2)">Arama Niyeti</label>
|
||
<input type="text" id="ai-anime-intent" class="form-control form-control-sm" readonly>
|
||
</div>
|
||
</div>
|
||
<div class="mt-2 text-end">
|
||
<button id="btn-ai-anime-save" class="btn btn-success btn-sm"><i class="bi bi-check2 me-1"></i>Kaydet</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Keyword Araştırması --}}
|
||
<div class="section-card">
|
||
<div class="section-card-header">
|
||
<i class="bi bi-search" style="color:var(--info)"></i>
|
||
<h6>AI Anahtar Kelime Araştırması</h6>
|
||
</div>
|
||
<div class="section-card-body">
|
||
<div class="d-flex gap-2 mb-3">
|
||
<input type="text" id="ai-kw-topic" class="form-control form-control-sm" placeholder="Konu girin (ör: naruto, isekai, shounen)" {{ !$aiConfigured?'disabled':'' }}>
|
||
<button id="btn-ai-kw-suggest" class="btn btn-info btn-sm text-dark" style="white-space:nowrap" {{ !$aiConfigured?'disabled':'' }}>
|
||
<i class="bi bi-search me-1"></i>Araştır
|
||
</button>
|
||
</div>
|
||
<div id="ai-kw-results" style="display:none"></div>
|
||
<div id="ai-kw-loading" style="display:none" class="text-center py-3 text-muted">
|
||
<div class="spinner-border spinner-border-sm me-2"></div>AI araştırıyor...
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Sayfa Analizi --}}
|
||
<div class="section-card">
|
||
<div class="section-card-header">
|
||
<i class="bi bi-file-earmark-search" style="color:var(--success)"></i>
|
||
<h6>AI Sayfa SEO Analizi</h6>
|
||
</div>
|
||
<div class="section-card-body">
|
||
<div class="row g-2 mb-2">
|
||
<div class="col-8">
|
||
<input type="url" id="ai-page-url" class="form-control form-control-sm" placeholder="https://animexe.com/anime/naruto" {{ !$aiConfigured?'disabled':'' }}>
|
||
</div>
|
||
<div class="col-4">
|
||
<button id="btn-ai-page-analyze" class="btn btn-success btn-sm w-100" {{ !$aiConfigured?'disabled':'' }}>
|
||
<i class="bi bi-magnifying-glass me-1"></i>Analiz Et
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div id="ai-page-results" style="display:none"></div>
|
||
<div id="ai-page-loading" style="display:none" class="text-center py-3 text-muted">
|
||
<div class="spinner-border spinner-border-sm me-2"></div>Sayfa analiz ediliyor...
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- FAQ Schema + İçerik Stratejisi --}}
|
||
<div class="row g-3">
|
||
<div class="col-md-6">
|
||
<div class="section-card h-100">
|
||
<div class="section-card-header">
|
||
<i class="bi bi-question-circle" style="color:#d29922"></i>
|
||
<h6 style="font-size:.82rem">FAQ Schema Üretici</h6>
|
||
</div>
|
||
<div class="section-card-body">
|
||
<select id="ai-faq-anime" class="form-select form-select-sm mb-2" {{ !$aiConfigured?'disabled':'' }}>
|
||
<option value="">— Anime seçin —</option>
|
||
@foreach(\App\Models\Anime::where('is_published',true)->orderBy('title')->take(100)->get(['id','title']) as $a)
|
||
<option value="{{ $a->id }}">{{ $a->title }}</option>
|
||
@endforeach
|
||
</select>
|
||
<button id="btn-ai-faq" class="btn btn-warning btn-sm w-100 text-dark" {{ !$aiConfigured?'disabled':'' }}>
|
||
<i class="bi bi-stars me-1"></i>FAQ Üret
|
||
</button>
|
||
<div id="ai-faq-results" class="mt-2" style="display:none"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="section-card h-100">
|
||
<div class="section-card-header">
|
||
<i class="bi bi-map" style="color:#f59e0b"></i>
|
||
<h6 style="font-size:.82rem">90 Günlük İçerik Stratejisi</h6>
|
||
</div>
|
||
<div class="section-card-body">
|
||
<p style="font-size:.78rem;color:var(--text2)">Mevcut SEO durumunuza göre 90 günlük detaylı bir SEO eylem planı oluşturun.</p>
|
||
<button id="btn-ai-strategy" class="btn btn-outline-warning btn-sm w-100" {{ !$aiConfigured?'disabled':'' }}>
|
||
<i class="bi bi-lightning me-1"></i>Strateji Oluştur
|
||
</button>
|
||
<div id="ai-strategy-result" class="mt-2" style="display:none;max-height:300px;overflow-y:auto;background:#010409;border:1px solid var(--border);border-radius:6px;padding:12px;font-size:.8rem;line-height:1.6"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>{{-- /content --}}
|
||
@endsection
|
||
|
||
@push('scripts')
|
||
<script>
|
||
// ── Tab System ─────────────────────────────────────────────────────────────
|
||
document.querySelectorAll('.seo-tab-btn').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
document.querySelectorAll('.seo-tab-btn').forEach(b => b.classList.remove('active'));
|
||
document.querySelectorAll('.seo-tab-pane').forEach(p => p.classList.remove('active'));
|
||
btn.classList.add('active');
|
||
document.getElementById('tab-' + btn.dataset.tab).classList.add('active');
|
||
if (window.location.hash !== '#' + btn.dataset.tab) {
|
||
history.replaceState(null, '', '#' + btn.dataset.tab);
|
||
}
|
||
});
|
||
});
|
||
// Open tab from URL hash
|
||
const hash = window.location.hash.replace('#','');
|
||
if (hash) { const btn = document.querySelector(`.seo-tab-btn[data-tab="${hash}"]`); if (btn) btn.click(); }
|
||
|
||
// ── Char Counters ──────────────────────────────────────────────────────────
|
||
function updateCounter(el, ctrId, okMin, okMax, max) {
|
||
const len = el.value.length;
|
||
const ctr = document.getElementById(ctrId);
|
||
if (!ctr) return;
|
||
ctr.textContent = len + '/' + max;
|
||
ctr.className = 'char-counter ' + (len < okMin ? 'warn' : len <= okMax ? 'ok' : 'bad');
|
||
}
|
||
// Init counters on load
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
const ht = document.getElementById('inp_home_title');
|
||
const hd = document.getElementById('inp_home_desc');
|
||
if (ht) updateCounter(ht, 'ctr_home_title', 50, 60, 70);
|
||
if (hd) updateCounter(hd, 'ctr_home_desc', 120, 160, 320);
|
||
updatePreview();
|
||
updateGuide();
|
||
});
|
||
|
||
// ── Preview ────────────────────────────────────────────────────────────────
|
||
function updatePreview() {
|
||
const title = document.getElementById('inp_home_title')?.value || '';
|
||
const desc = document.getElementById('inp_home_desc')?.value || '';
|
||
const dt = desc.substring(0, 155) + (desc.length > 155 ? '...' : '');
|
||
const dm = desc.substring(0, 100) + (desc.length > 100 ? '...' : '');
|
||
['prev_title','prev_title_mob'].forEach(id => { const el = document.getElementById(id); if (el) el.textContent = title; });
|
||
['prev_desc','prev_desc_mob'].forEach((id,i) => { const el = document.getElementById(id); if (el) el.textContent = i===0?dt:dm; });
|
||
updateGuide();
|
||
}
|
||
function updateGuide() {
|
||
const tl = document.getElementById('inp_home_title')?.value.length || 0;
|
||
const dl = document.getElementById('inp_home_desc')?.value.length || 0;
|
||
const setGuide = (txtId, barId, len, max, ok1, ok2) => {
|
||
const txt = document.getElementById(txtId); const bar = document.getElementById(barId);
|
||
if (txt) txt.textContent = len + '/' + max;
|
||
if (bar) { bar.style.width = Math.min(len/max*100,100)+'%'; bar.className = 'progress-bar ' + (len<ok1?'bg-warning':len<=ok2?'bg-success':'bg-danger'); }
|
||
};
|
||
setGuide('guide_title','bar_title',tl,70,50,60);
|
||
setGuide('guide_desc','bar_desc',dl,320,120,160);
|
||
}
|
||
function resetRobots() {
|
||
document.querySelector('.robots-editor').value = `User-agent: *\nDisallow: /admin\nDisallow: /api\nDisallow: /storage\n\nSitemap: https://animexe.com/sitemap.xml`;
|
||
}
|
||
|
||
// ── Redirect toggle ────────────────────────────────────────────────────────
|
||
document.querySelectorAll('.btn-toggle-redirect').forEach(btn => {
|
||
btn.addEventListener('click', async () => {
|
||
const id = btn.dataset.id;
|
||
const r = await fetch(`{{ url('admin/seo/redirects') }}/${id}/toggle`, {
|
||
method: 'POST',
|
||
headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content }
|
||
});
|
||
const d = await r.json();
|
||
btn.textContent = d.is_active ? 'Aktif' : 'Pasif';
|
||
btn.className = 'btn btn-sm btn-toggle-redirect ' + (d.is_active ? 'btn-success' : 'btn-secondary');
|
||
btn.closest('tr').className = 'redirect-row' + (d.is_active ? '' : ' inactive');
|
||
});
|
||
});
|
||
|
||
// ── Auto SEO per anime ─────────────────────────────────────────────────────
|
||
document.querySelectorAll('.btn-auto-seo').forEach(btn => {
|
||
btn.addEventListener('click', async () => {
|
||
const id = btn.dataset.id;
|
||
const row = document.getElementById('anime-row-' + id);
|
||
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span>';
|
||
try {
|
||
const r = await fetch(`{{ url('admin/seo/anime') }}/${id}/generate`, {
|
||
method: 'POST',
|
||
headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content }
|
||
});
|
||
const d = await r.json();
|
||
if (d.seo_title) row.querySelector('[name$="[seo_title]"]').value = d.seo_title;
|
||
if (d.seo_meta_desc) row.querySelector('[name$="[seo_meta_desc]"]').value = d.seo_meta_desc;
|
||
if (d.seo_keywords) row.querySelector('[name$="[seo_keywords]"]').value = d.seo_keywords;
|
||
btn.innerHTML = '<i class="bi bi-check" style="font-size:.75rem;color:var(--success)"></i>';
|
||
} catch(e) { btn.innerHTML = '<i class="bi bi-x" style="font-size:.75rem;color:var(--danger)"></i>'; }
|
||
});
|
||
});
|
||
|
||
// ── Toplu Doldurma (Batch + Polling) ─────────────────────────────────────────
|
||
|
||
const BF_BATCH_SIZES = { template_seo: 50, ai_seo: 5, ai_meta: 5, ai_all: 3 };
|
||
const BF_ROUTE = '{{ route("admin.seo.bulk-fill-batch") }}';
|
||
const BF_STATS_ROUTE = '{{ route("admin.seo.bulk-fill-stats") }}';
|
||
const BF_CSRF = document.querySelector('meta[name=csrf-token]')?.content || '';
|
||
|
||
let bfRunning = false;
|
||
let bfShouldStop = false;
|
||
|
||
async function loadBulkFillStats() {
|
||
try {
|
||
const d = await (await fetch(BF_STATS_ROUTE)).json();
|
||
document.getElementById('bf-pct-seo').textContent = d.pct_seo + '%';
|
||
document.getElementById('bf-pct-desc').textContent = d.pct_desc + '%';
|
||
document.getElementById('bf-needs-seo').textContent = d.needs_seo;
|
||
document.getElementById('bf-needs-meta').textContent = d.needs_meta;
|
||
document.getElementById('bf-coverage-badge').textContent = `${d.total} anime`;
|
||
|
||
const pSeo = d.pct_seo;
|
||
document.getElementById('bf-pct-seo').style.color = pSeo >= 90 ? 'var(--success)' : pSeo >= 50 ? 'var(--warning)' : 'var(--danger)';
|
||
} catch(e) {}
|
||
}
|
||
loadBulkFillStats();
|
||
|
||
function stopBulkFill() {
|
||
bfShouldStop = true;
|
||
document.getElementById('bf-progress-label').textContent = 'Durduruluyor...';
|
||
}
|
||
|
||
async function startBulkFill(mode) {
|
||
if (bfRunning) { alert('Zaten çalışıyor!'); return; }
|
||
|
||
const modeLabels = {
|
||
template_seo: 'Hızlı SEO (template)',
|
||
ai_seo: 'AI SEO',
|
||
ai_meta: 'AI Meta Doldurma',
|
||
ai_all: 'Tam Doldurma (Meta + SEO)',
|
||
};
|
||
|
||
if (!confirm(`${modeLabels[mode]} — tüm yayındaki animelere uygulanacak.\n\nBu işlem birkaç dakika sürebilir. Devam edilsin mi?`)) return;
|
||
|
||
bfRunning = true;
|
||
bfShouldStop = false;
|
||
const force = document.getElementById('bf-force').checked;
|
||
const batchSize = BF_BATCH_SIZES[mode] || 5;
|
||
|
||
const area = document.getElementById('bf-progress-area');
|
||
const bar = document.getElementById('bf-progress-bar');
|
||
const label = document.getElementById('bf-progress-label');
|
||
const count = document.getElementById('bf-progress-count');
|
||
const log = document.getElementById('bf-log');
|
||
const stopBtn = document.getElementById('bf-stop-btn');
|
||
|
||
area.style.display = 'block';
|
||
stopBtn.classList.remove('d-none');
|
||
bar.style.width = '0%';
|
||
log.innerHTML = '';
|
||
|
||
let totalDone = 0, totalErrors = 0, lastId = 0, total = 0;
|
||
|
||
const addLog = (msg) => {
|
||
const line = document.createElement('div');
|
||
line.textContent = new Date().toLocaleTimeString('tr-TR') + ' — ' + msg;
|
||
log.prepend(line);
|
||
};
|
||
|
||
addLog(`${modeLabels[mode]} başlatıldı (batch: ${batchSize})`);
|
||
|
||
while (!bfShouldStop) {
|
||
try {
|
||
const r = await fetch(BF_ROUTE, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': BF_CSRF },
|
||
body: JSON.stringify({ mode, last_id: lastId, batch_size: batchSize, force }),
|
||
});
|
||
|
||
if (!r.ok) {
|
||
const err = await r.json().catch(() => ({}));
|
||
addLog('❌ Hata: ' + (err.error || r.status));
|
||
break;
|
||
}
|
||
|
||
const d = await r.json();
|
||
|
||
totalDone += d.done || 0;
|
||
totalErrors += d.errors || 0;
|
||
lastId = d.last_id || lastId;
|
||
total = (totalDone + totalErrors + (d.remaining || 0));
|
||
|
||
const pct = total > 0 ? Math.min(100, Math.round(totalDone / total * 100)) : 100;
|
||
bar.style.width = pct + '%';
|
||
count.textContent = `${totalDone} / ${total}`;
|
||
label.textContent = `${modeLabels[mode]} — %${pct} tamamlandı`;
|
||
|
||
if (d.done > 0 || d.errors > 0) {
|
||
addLog(`${d.done} işlendi${d.errors ? ', ' + d.errors + ' hata' : ''} (last_id: ${lastId})`);
|
||
}
|
||
|
||
if (d.finished || d.remaining <= 0) {
|
||
label.textContent = `✅ Tamamlandı! ${totalDone} anime işlendi${totalErrors ? ', ' + totalErrors + ' hata' : ''}.`;
|
||
bar.style.background = 'var(--success)';
|
||
addLog('Tamamlandı!');
|
||
break;
|
||
}
|
||
|
||
// Sonraki batch için kısa bekleme
|
||
if (mode !== 'template_seo') {
|
||
await new Promise(res => setTimeout(res, 500));
|
||
}
|
||
|
||
} catch(e) {
|
||
addLog('❌ Bağlantı hatası: ' + e.message);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (bfShouldStop) {
|
||
addLog('⏹ Durduruldu.');
|
||
label.textContent = `Durduruldu. ${totalDone} anime işlendi.`;
|
||
}
|
||
|
||
bfRunning = false;
|
||
bfShouldStop = false;
|
||
stopBtn.classList.add('d-none');
|
||
|
||
// İstatistikleri yenile
|
||
await loadBulkFillStats();
|
||
// Tablo 1.5s sonra yenile (sayfa yenileme yerine soft)
|
||
if (totalDone > 0) setTimeout(() => location.reload(), 2000);
|
||
}
|
||
|
||
// ── Analytics embed ────────────────────────────────────────────────────────
|
||
function loadEmbed() {
|
||
const url = document.getElementById('embedUrl').value.trim();
|
||
const container = document.getElementById('embedContainer');
|
||
if (!url) return;
|
||
container.innerHTML = '<iframe src="' + url + '" style="width:100%;height:600px;border:0" allowfullscreen></iframe>';
|
||
}
|
||
async function saveEmbedUrl() {
|
||
const url = document.getElementById('embedUrl').value.trim();
|
||
const btn = event.target;
|
||
btn.innerHTML = '<i class="bi bi-hourglass-split me-1"></i>Kaydediliyor...';
|
||
btn.disabled = true;
|
||
try {
|
||
const form = new FormData();
|
||
form.append('_token', document.querySelector('meta[name=csrf-token]').content);
|
||
form.append('seo_looker_embed_url', url);
|
||
await fetch('{{ route("admin.seo.update") }}', { method:'POST', body: form });
|
||
btn.innerHTML = '<i class="bi bi-check-lg me-1"></i>Kaydedildi';
|
||
setTimeout(() => { btn.innerHTML = '<i class="bi bi-save me-1"></i>Kaydet'; btn.disabled = false; }, 2000);
|
||
} catch(e) { btn.innerHTML = '<i class="bi bi-save me-1"></i>Kaydet'; btn.disabled = false; }
|
||
}
|
||
|
||
// ── PageSpeed ──────────────────────────────────────────────────────────────
|
||
let psiStrategy = 'mobile';
|
||
document.querySelectorAll('.psi-strat').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
document.querySelectorAll('.psi-strat').forEach(b => b.classList.remove('active','btn-primary'));
|
||
btn.classList.add('active','btn-primary');
|
||
psiStrategy = btn.dataset.strat;
|
||
});
|
||
});
|
||
|
||
document.getElementById('btn-psi-run')?.addEventListener('click', async () => {
|
||
const url = document.getElementById('psi-url').value.trim();
|
||
if (!url) { alert('URL girin'); return; }
|
||
document.getElementById('psi-placeholder').style.display = 'none';
|
||
document.getElementById('psi-results').style.display = 'none';
|
||
document.getElementById('psi-loading').style.display = 'block';
|
||
|
||
try {
|
||
const r = await fetch('{{ route("admin.seo.pagespeed") }}', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type':'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content },
|
||
body: JSON.stringify({ url, strategy: psiStrategy })
|
||
});
|
||
const d = await r.json();
|
||
document.getElementById('psi-loading').style.display = 'none';
|
||
|
||
if (d.error) { alert(d.error); document.getElementById('psi-placeholder').style.display='block'; return; }
|
||
|
||
// Scores
|
||
const scoreLabels = { performance:'Performans', accessibility:'Erişilebilirlik', seo:'SEO', best_practices:'En İyi Uyg.' };
|
||
document.getElementById('psi-scores').innerHTML = Object.entries(d.scores).map(([k,v]) => {
|
||
const cls = v>=90?'good':v>=50?'average':'poor';
|
||
return `<div class="text-center"><div class="psi-score ${cls}">${v}</div><div style="font-size:.72rem;color:var(--text2);margin-top:6px">${scoreLabels[k]||k}</div></div>`;
|
||
}).join('');
|
||
|
||
// Vitals
|
||
const vitLabels = { fcp:'FCP (First Paint)', lcp:'LCP (Largest Paint)', cls:'CLS (Layout Shift)', tbt:'TBT (Blocking Time)' };
|
||
document.getElementById('psi-vitals').innerHTML = Object.entries(d.vitals).filter(([,v])=>v).map(([k,v]) =>
|
||
`<div class="col-6"><div style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:10px 14px"><div style="font-size:1.1rem;font-weight:700;color:var(--text)">${v}</div><div style="font-size:.72rem;color:var(--text2)">${vitLabels[k]||k}</div></div></div>`
|
||
).join('');
|
||
|
||
// Opportunities
|
||
if (d.opportunities?.length) {
|
||
document.getElementById('psi-opportunities').innerHTML = '<div style="font-size:.82rem;font-weight:600;margin-bottom:8px;color:var(--text2)">İyileştirme Fırsatları</div>' +
|
||
d.opportunities.map(o =>
|
||
`<div style="background:var(--surface);border:1px solid var(--border);border-radius:6px;padding:10px 14px;margin-bottom:6px">
|
||
<div style="font-size:.83rem;font-weight:600">${o.title}</div>
|
||
${o.savings ? `<span class="badge bg-warning text-dark" style="font-size:.7rem">~${Math.round(o.savings)}ms tasarruf</span>` : ''}
|
||
</div>`
|
||
).join('');
|
||
}
|
||
|
||
document.getElementById('psi-results').style.display = 'block';
|
||
} catch(e) {
|
||
document.getElementById('psi-loading').style.display = 'none';
|
||
document.getElementById('psi-placeholder').style.display = 'block';
|
||
alert('Hata: ' + e.message);
|
||
}
|
||
});
|
||
|
||
// ── Duplicate content check ────────────────────────────────────────────────
|
||
document.getElementById('btn-dup-check')?.addEventListener('click', async () => {
|
||
const btn = document.getElementById('btn-dup-check');
|
||
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Kontrol ediliyor...';
|
||
btn.disabled = true;
|
||
try {
|
||
const r = await fetch('{{ route("admin.seo.duplicate-content") }}');
|
||
const d = await r.json();
|
||
const box = document.getElementById('dup-results');
|
||
if (!d.length) {
|
||
box.innerHTML = '<div class="alert alert-success"><i class="bi bi-check-circle me-1"></i>Tekrarlayan içerik yok.</div>';
|
||
} else {
|
||
box.innerHTML = d.map(g =>
|
||
`<div style="background:var(--surface);border:1px solid var(--border2);border-radius:6px;padding:10px;margin-bottom:6px">
|
||
<div style="font-size:.78rem;font-weight:600;color:var(--danger)">${g.cnt} anime aynı açıklamayı paylaşıyor</div>
|
||
<div style="font-size:.75rem;color:var(--text2)">${g.titles}</div>
|
||
<div style="font-size:.72rem;color:var(--info);margin-top:4px">"${(g.description||'').substring(0,80)}..."</div>
|
||
</div>`
|
||
).join('');
|
||
}
|
||
box.style.display = 'block';
|
||
btn.innerHTML = '<i class="bi bi-search me-1"></i>Tekrarlayan İçerikleri Listele';
|
||
btn.disabled = false;
|
||
} catch(e) { btn.innerHTML = '<i class="bi bi-search me-1"></i>Tekrarlayan İçerikleri Listele'; btn.disabled = false; }
|
||
});
|
||
|
||
// ── Internal links ─────────────────────────────────────────────────────────
|
||
document.getElementById('btn-internal-links')?.addEventListener('click', async () => {
|
||
const btn = document.getElementById('btn-internal-links');
|
||
btn.disabled = true;
|
||
document.getElementById('link-loading').style.display = 'block';
|
||
document.getElementById('link-results').style.display = 'none';
|
||
try {
|
||
const r = await fetch('{{ route("admin.seo.internal-links") }}');
|
||
const d = await r.json();
|
||
const box = document.getElementById('link-results');
|
||
box.innerHTML = '<div style="font-size:.78rem;font-weight:600;color:var(--text2);margin-bottom:6px">Hiç atıflanmayan animeler (Orphaned Pages)</div>' +
|
||
d.filter(a => a.mentioned_in === 0).slice(0,20).map(a =>
|
||
`<div style="display:flex;justify-content:space-between;padding:6px 10px;background:var(--surface);border:1px solid var(--border);border-radius:4px;margin-bottom:4px;font-size:.78rem">
|
||
<span><a href="/anime/${a.slug}" target="_blank" style="color:var(--info)">${a.title}</a></span>
|
||
<span class="badge bg-danger" style="font-size:.65rem">0 atıf</span>
|
||
</div>`
|
||
).join('') || '<div class="text-muted text-center">Tüm animeler atıflanıyor!</div>';
|
||
box.style.display = 'block';
|
||
document.getElementById('link-loading').style.display = 'none';
|
||
btn.disabled = false;
|
||
} catch(e) { document.getElementById('link-loading').style.display = 'none'; btn.disabled = false; }
|
||
});
|
||
|
||
// ── Re-audit ───────────────────────────────────────────────────────────────
|
||
document.getElementById('btn-reaudit')?.addEventListener('click', async () => {
|
||
const btn = document.getElementById('btn-reaudit');
|
||
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>';
|
||
btn.disabled = true;
|
||
try {
|
||
const r = await fetch('{{ route("admin.seo.audit") }}');
|
||
const d = await r.json();
|
||
const scoreEl = document.querySelector('.score-num');
|
||
if (scoreEl) scoreEl.textContent = d.score;
|
||
btn.innerHTML = '<i class="bi bi-arrow-clockwise me-1"></i>Yenile';
|
||
btn.disabled = false;
|
||
setTimeout(() => location.reload(), 500);
|
||
} catch(e) { btn.disabled = false; btn.innerHTML = '<i class="bi bi-arrow-clockwise me-1"></i>Yenile'; }
|
||
});
|
||
|
||
// ══════════════════════════════════════════════════════════════════════════
|
||
// AI ASISTAN
|
||
// ══════════════════════════════════════════════════════════════════════════
|
||
|
||
const CSRF = document.querySelector('meta[name=csrf-token]')?.content || '';
|
||
const aiChatUrl = '{{ route("admin.seo.ai.chat") }}';
|
||
const aiAnimeGenUrl = '{{ url("admin/seo/ai/anime") }}';
|
||
const aiKwSuggestUrl = '{{ route("admin.seo.ai.keyword-suggest") }}';
|
||
const aiPageUrl = '{{ route("admin.seo.ai.page-analysis") }}';
|
||
const aiFaqUrl = '{{ route("admin.seo.ai.faq-schema") }}';
|
||
const aiStrategyUrl = '{{ route("admin.seo.ai.content-strategy") }}';
|
||
|
||
// ── Chat ──────────────────────────────────────────────────────────────────
|
||
let chatHistory = [];
|
||
|
||
function addChatMessage(role, html, isTyping = false) {
|
||
const box = document.getElementById('ai-chat-messages');
|
||
const wrap = document.createElement('div');
|
||
wrap.className = 'ai-msg ' + role;
|
||
const avatar = role === 'assistant'
|
||
? '<div class="ai-avatar"><i class="bi bi-stars"></i></div>'
|
||
: '<div class="ai-avatar">A</div>';
|
||
const bubble = isTyping
|
||
? `<div class="ai-bubble ai-typing"><span></span><span></span><span></span></div>`
|
||
: `<div class="ai-bubble">${html}</div>`;
|
||
wrap.innerHTML = avatar + bubble;
|
||
box.appendChild(wrap);
|
||
box.scrollTop = box.scrollHeight;
|
||
return wrap;
|
||
}
|
||
|
||
function mdToHtml(text) {
|
||
return text
|
||
.replace(/\*\*(.*?)\*\*/g, '<b>$1</b>')
|
||
.replace(/\*(.*?)\*/g, '<em>$1</em>')
|
||
.replace(/`([^`]+)`/g, '<code>$1</code>')
|
||
.replace(/^### (.+)$/gm, '<h4>$1</h4>')
|
||
.replace(/^## (.+)$/gm, '<h3>$1</h3>')
|
||
.replace(/^• (.+)$/gm, '• $1<br>')
|
||
.replace(/^- (.+)$/gm, '• $1<br>')
|
||
.replace(/\n\n/g, '<br><br>')
|
||
.replace(/\n/g, '<br>');
|
||
}
|
||
|
||
async function sendAiChat(message) {
|
||
chatHistory.push({ role: 'user', content: message });
|
||
addChatMessage('user', escapeHtml(message));
|
||
const typingEl = addChatMessage('assistant', '', true);
|
||
|
||
try {
|
||
const r = await fetch(aiChatUrl, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': CSRF },
|
||
body: JSON.stringify({ messages: chatHistory })
|
||
});
|
||
const d = await r.json();
|
||
typingEl.remove();
|
||
if (d.error) { addChatMessage('assistant', `<span style="color:var(--danger)">${escapeHtml(d.error)}</span>`); return; }
|
||
chatHistory.push({ role: 'assistant', content: d.reply });
|
||
addChatMessage('assistant', mdToHtml(d.reply));
|
||
} catch(e) {
|
||
typingEl.remove();
|
||
addChatMessage('assistant', `<span style="color:var(--danger)">Bağlantı hatası: ${escapeHtml(e.message)}</span>`);
|
||
}
|
||
}
|
||
|
||
document.getElementById('btn-ai-send')?.addEventListener('click', () => {
|
||
const inp = document.getElementById('ai-chat-input');
|
||
const msg = inp.value.trim();
|
||
if (!msg) return;
|
||
inp.value = '';
|
||
inp.style.height = '';
|
||
sendAiChat(msg);
|
||
});
|
||
|
||
document.getElementById('ai-chat-input')?.addEventListener('keydown', e => {
|
||
if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); document.getElementById('btn-ai-send').click(); }
|
||
});
|
||
|
||
document.querySelectorAll('.btn-quick-prompt').forEach(btn => {
|
||
btn.addEventListener('click', () => sendAiChat(btn.textContent.trim()));
|
||
});
|
||
|
||
// ── AI Anime SEO Üretici ──────────────────────────────────────────────────
|
||
let aiAnimeCurrentId = null;
|
||
let aiAnimeResult = null;
|
||
|
||
document.getElementById('btn-ai-anime-gen')?.addEventListener('click', async () => {
|
||
const sel = document.getElementById('ai-anime-select');
|
||
const id = sel.value;
|
||
if (!id) { alert('Lütfen bir anime seçin.'); return; }
|
||
aiAnimeCurrentId = id;
|
||
const btn = document.getElementById('btn-ai-anime-gen');
|
||
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>AI çalışıyor...';
|
||
btn.disabled = true;
|
||
document.getElementById('ai-anime-result').style.display = 'none';
|
||
|
||
try {
|
||
const r = await fetch(`${aiAnimeGenUrl}/${id}/generate`, {
|
||
method: 'POST',
|
||
headers: { 'X-CSRF-TOKEN': CSRF }
|
||
});
|
||
const d = await r.json();
|
||
if (d.error) { alert(d.error); return; }
|
||
aiAnimeResult = d;
|
||
document.getElementById('ai-anime-title-out').value = d.seo_title || '';
|
||
document.getElementById('ai-anime-desc-out').value = d.seo_meta_desc || '';
|
||
document.getElementById('ai-anime-kw-out').value = d.seo_keywords || '';
|
||
document.getElementById('ai-anime-primary-kw').value = d.primary_keyword || '';
|
||
document.getElementById('ai-anime-intent').value = d.search_intent || '';
|
||
const tl = (d.seo_title||'').length;
|
||
const dl = (d.seo_meta_desc||'').length;
|
||
document.getElementById('ai-anime-title-len').textContent = `${tl} karakter ${tl>=50&&tl<=65?'✓ İdeal':'(ideal: 50-65)'}`;
|
||
document.getElementById('ai-anime-title-len').style.color = tl>=50&&tl<=65?'var(--success)':'#d29922';
|
||
document.getElementById('ai-anime-desc-len').textContent = `${dl} karakter ${dl>=145&&dl<=158?'✓ İdeal':'(ideal: 145-158)'}`;
|
||
document.getElementById('ai-anime-desc-len').style.color = dl>=145&&dl<=158?'var(--success)':'#d29922';
|
||
document.getElementById('ai-anime-result').style.display = 'block';
|
||
} catch(e) { alert('Hata: ' + e.message); }
|
||
finally { btn.innerHTML = '<i class="bi bi-stars me-1"></i>AI ile Oluştur'; btn.disabled = false; }
|
||
});
|
||
|
||
document.getElementById('btn-ai-anime-save')?.addEventListener('click', async () => {
|
||
if (!aiAnimeCurrentId || !aiAnimeResult) return;
|
||
const btn = document.getElementById('btn-ai-anime-save');
|
||
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>';
|
||
btn.disabled = true;
|
||
try {
|
||
// Already saved by the generate endpoint — just show success
|
||
btn.innerHTML = '<i class="bi bi-check2 me-1"></i>Kaydedildi!';
|
||
btn.className = 'btn btn-success btn-sm';
|
||
// Update the select option label
|
||
const opt = document.querySelector(`#ai-anime-select option[value="${aiAnimeCurrentId}"]`);
|
||
if (opt && !opt.textContent.includes('✓')) opt.textContent += ' ✓';
|
||
setTimeout(() => { btn.innerHTML = '<i class="bi bi-check2 me-1"></i>Kaydet'; btn.disabled = false; btn.className = 'btn btn-success btn-sm'; }, 2000);
|
||
} catch(e) { btn.innerHTML = '<i class="bi bi-check2 me-1"></i>Kaydet'; btn.disabled = false; }
|
||
});
|
||
|
||
// ── Keyword Araştırması ───────────────────────────────────────────────────
|
||
document.getElementById('btn-ai-kw-suggest')?.addEventListener('click', async () => {
|
||
const topic = document.getElementById('ai-kw-topic').value.trim();
|
||
if (!topic) return;
|
||
const btn = document.getElementById('btn-ai-kw-suggest');
|
||
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span>';
|
||
btn.disabled = true;
|
||
document.getElementById('ai-kw-loading').style.display = 'block';
|
||
document.getElementById('ai-kw-results').style.display = 'none';
|
||
|
||
try {
|
||
const r = await fetch(aiKwSuggestUrl, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type':'application/json', 'X-CSRF-TOKEN': CSRF },
|
||
body: JSON.stringify({ topic })
|
||
});
|
||
const d = await r.json();
|
||
document.getElementById('ai-kw-loading').style.display = 'none';
|
||
if (d.error) { alert(d.error); return; }
|
||
|
||
const kwGroups = [
|
||
['head', '🔥 Head Keywords (Yüksek Hacim)', 'var(--danger)'],
|
||
['body', '⚡ Body Keywords (Orta Hacim)', '#d29922'],
|
||
['long_tail', '🎯 Long-tail (Düşük Rekabet)', 'var(--success)'],
|
||
['questions', '❓ Soru Formatları (Featured Snippet)','#58a6ff'],
|
||
];
|
||
|
||
let html = '';
|
||
for (const [key, label, color] of kwGroups) {
|
||
if (!d[key]?.length) continue;
|
||
html += `<div class="mb-3"><div style="font-size:.78rem;font-weight:600;color:${color};margin-bottom:6px">${label}</div><div>`;
|
||
for (const kw of d[key]) {
|
||
const diff = kw.difficulty ?? '?';
|
||
const diffC = diff<=33?'var(--success)':diff<=66?'#d29922':'var(--danger)';
|
||
html += `<span class="ai-kw-badge" onclick="addKwToTracker(this)" data-kw="${escapeHtml(kw.keyword)}" data-vol="${kw.volume||''}" data-diff="${diff}">
|
||
${escapeHtml(kw.keyword)}
|
||
<span class="kw-vol">${kw.volume||''}</span>
|
||
<span class="kw-diff" style="color:${diffC}">${diff}</span>
|
||
</span>`;
|
||
}
|
||
html += '</div></div>';
|
||
}
|
||
|
||
if (d.content_ideas?.length) {
|
||
html += `<div class="mt-2" style="background:var(--surface);border:1px solid var(--border);border-radius:6px;padding:10px">
|
||
<div style="font-size:.75rem;font-weight:600;color:var(--text2);margin-bottom:6px">💡 İçerik Fikirleri</div>`;
|
||
for (const idea of d.content_ideas) {
|
||
html += `<div style="font-size:.78rem;color:var(--text);margin-bottom:4px">• ${escapeHtml(idea)}</div>`;
|
||
}
|
||
html += '</div>';
|
||
}
|
||
|
||
const box = document.getElementById('ai-kw-results');
|
||
box.innerHTML = html + '<div style="font-size:.7rem;color:var(--text2);margin-top:6px">Rozete tıklayarak anahtar kelime takip listesine ekleyin.</div>';
|
||
box.style.display = 'block';
|
||
} catch(e) { document.getElementById('ai-kw-loading').style.display = 'none'; alert(e.message); }
|
||
finally { btn.innerHTML = '<i class="bi bi-search me-1"></i>Araştır'; btn.disabled = false; }
|
||
});
|
||
|
||
document.getElementById('ai-kw-topic')?.addEventListener('keydown', e => {
|
||
if (e.key === 'Enter') document.getElementById('btn-ai-kw-suggest').click();
|
||
});
|
||
|
||
async function addKwToTracker(el) {
|
||
const kw = el.dataset.kw;
|
||
try {
|
||
await fetch('{{ route("admin.seo.keywords.store") }}', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type':'application/json', 'X-CSRF-TOKEN': CSRF },
|
||
body: JSON.stringify({ keyword: kw })
|
||
});
|
||
el.style.background = '#238636'; el.style.borderColor = '#238636'; el.style.color = '#fff';
|
||
el.setAttribute('title', 'Listeye eklendi!');
|
||
} catch(e) {}
|
||
}
|
||
|
||
// ── Sayfa Analizi ─────────────────────────────────────────────────────────
|
||
document.getElementById('btn-ai-page-analyze')?.addEventListener('click', async () => {
|
||
const url = document.getElementById('ai-page-url').value.trim();
|
||
if (!url) return;
|
||
const btn = document.getElementById('btn-ai-page-analyze');
|
||
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span>';
|
||
btn.disabled = true;
|
||
document.getElementById('ai-page-loading').style.display = 'block';
|
||
document.getElementById('ai-page-results').style.display = 'none';
|
||
|
||
try {
|
||
const r = await fetch(aiPageUrl, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type':'application/json', 'X-CSRF-TOKEN': CSRF },
|
||
body: JSON.stringify({ url })
|
||
});
|
||
const d = await r.json();
|
||
document.getElementById('ai-page-loading').style.display = 'none';
|
||
if (d.error) { alert(d.error); return; }
|
||
|
||
const scoreColor = s => s>=80?'var(--success)':s>=60?'#d29922':'var(--danger)';
|
||
let html = `<div style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:14px;margin-bottom:8px">
|
||
<div class="d-flex align-items-center gap-3 mb-3">
|
||
<div style="font-size:2rem;font-weight:800;color:${scoreColor(d.overall_score)}">${d.overall_score}</div>
|
||
<div><div style="font-size:.82rem;font-weight:600">Genel SEO Skoru</div><div style="font-size:.72rem;color:var(--text2)">${url}</div></div>
|
||
</div>`;
|
||
|
||
if (d.quick_wins?.length) {
|
||
html += `<div style="font-size:.78rem;font-weight:600;color:var(--success);margin-bottom:4px">⚡ Hızlı Kazançlar</div>`;
|
||
for (const win of d.quick_wins) html += `<div style="font-size:.78rem;color:var(--text);margin-bottom:2px">✓ ${escapeHtml(win)}</div>`;
|
||
}
|
||
if (d.priority_actions?.length) {
|
||
html += `<div style="font-size:.78rem;font-weight:600;color:var(--danger);margin:8px 0 4px">🎯 Öncelikli Aksiyonlar</div>`;
|
||
d.priority_actions.forEach((a,i) => { html += `<div style="font-size:.78rem;color:var(--text);margin-bottom:2px">${i+1}. ${escapeHtml(a)}</div>`; });
|
||
}
|
||
if (d.technical_issues?.length) {
|
||
html += `<div style="font-size:.78rem;font-weight:600;color:#d29922;margin:8px 0 4px">⚠ Teknik Sorunlar</div>`;
|
||
for (const issue of d.technical_issues) html += `<div style="font-size:.78rem;color:var(--text2);margin-bottom:2px">• ${escapeHtml(issue)}</div>`;
|
||
}
|
||
html += '</div>';
|
||
|
||
const box = document.getElementById('ai-page-results');
|
||
box.innerHTML = html;
|
||
box.style.display = 'block';
|
||
} catch(e) { document.getElementById('ai-page-loading').style.display = 'none'; alert(e.message); }
|
||
finally { btn.innerHTML = '<i class="bi bi-magnifying-glass me-1"></i>Analiz Et'; btn.disabled = false; }
|
||
});
|
||
|
||
// ── FAQ Schema ────────────────────────────────────────────────────────────
|
||
document.getElementById('btn-ai-faq')?.addEventListener('click', async () => {
|
||
const animeId = document.getElementById('ai-faq-anime').value;
|
||
if (!animeId) { alert('Bir anime seçin.'); return; }
|
||
const btn = document.getElementById('btn-ai-faq');
|
||
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Üretiliyor...';
|
||
btn.disabled = true;
|
||
|
||
try {
|
||
const r = await fetch(aiFaqUrl, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type':'application/json', 'X-CSRF-TOKEN': CSRF },
|
||
body: JSON.stringify({ anime_id: animeId })
|
||
});
|
||
const d = await r.json();
|
||
if (d.error) { alert(d.error); return; }
|
||
|
||
const faqs = d.faqs || [];
|
||
const schemaJson = JSON.stringify({
|
||
"@@context":"https://schema.org",
|
||
"@@type":"FAQPage",
|
||
"mainEntity": faqs.map(f=>({ "@@type":"Question","name":f.question,"acceptedAnswer":{"@@type":"Answer","text":f.answer} }))
|
||
}, null, 2);
|
||
|
||
let html = '<div style="font-size:.75rem;font-weight:600;color:var(--text2);margin-bottom:6px">Üretilen FAQ\'lar:</div>';
|
||
for (const faq of faqs) {
|
||
html += `<div style="background:var(--surface);border:1px solid var(--border);border-radius:6px;padding:8px 12px;margin-bottom:6px">
|
||
<div style="font-size:.78rem;font-weight:600;color:var(--text)">${escapeHtml(faq.question)}</div>
|
||
<div style="font-size:.75rem;color:var(--text2);margin-top:3px">${escapeHtml(faq.answer)}</div>
|
||
</div>`;
|
||
}
|
||
html += `<details style="margin-top:8px"><summary style="font-size:.75rem;color:var(--info);cursor:pointer">JSON-LD Schema Kodu</summary>
|
||
<pre style="font-size:.7rem;background:#010409;border:1px solid var(--border);border-radius:6px;padding:8px;overflow-x:auto;white-space:pre-wrap;color:var(--info)">${escapeHtml(schemaJson)}</pre>
|
||
</details>`;
|
||
|
||
const box = document.getElementById('ai-faq-results');
|
||
box.innerHTML = html;
|
||
box.style.display = 'block';
|
||
} catch(e) { alert(e.message); }
|
||
finally { btn.innerHTML = '<i class="bi bi-stars me-1"></i>FAQ Üret'; btn.disabled = false; }
|
||
});
|
||
|
||
// ── İçerik Stratejisi ─────────────────────────────────────────────────────
|
||
document.getElementById('btn-ai-strategy')?.addEventListener('click', async () => {
|
||
const btn = document.getElementById('btn-ai-strategy');
|
||
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Strateji oluşturuluyor...';
|
||
btn.disabled = true;
|
||
document.getElementById('ai-strategy-result').style.display = 'none';
|
||
|
||
try {
|
||
const r = await fetch(aiStrategyUrl, {
|
||
method: 'POST',
|
||
headers: { 'X-CSRF-TOKEN': CSRF }
|
||
});
|
||
const d = await r.json();
|
||
if (d.error) { alert(d.error); return; }
|
||
const box = document.getElementById('ai-strategy-result');
|
||
box.innerHTML = mdToHtml(d.strategy || '');
|
||
box.style.display = 'block';
|
||
} catch(e) { alert(e.message); }
|
||
finally { btn.innerHTML = '<i class="bi bi-lightning me-1"></i>Strateji Oluştur'; btn.disabled = false; }
|
||
});
|
||
|
||
// ── Yardımcılar ───────────────────────────────────────────────────────────
|
||
function escapeHtml(str) {
|
||
return String(str||'').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||
}
|
||
</script>
|
||
@endpush
|