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

249 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@extends('admin.layouts.app')
@section('title', isset($blog->id) ? 'Blog Düzenle' : 'Yeni Blog Yazısı')
@section('page-title', isset($blog->id) ? 'Blog Yazısı Düzenle' : 'Yeni Blog Yazısı')
@push('styles')
<style>
.char-counter{font-size:.72rem;color:var(--text2);text-align:right}
.char-counter.warn{color:#d97706}
.char-counter.danger{color:#ef4444}
.seo-preview{background:var(--bg2);border:1px solid var(--border);border-radius:8px;padding:16px;margin-top:12px}
.seo-preview .sp-url{color:#4ade80;font-size:.78rem;margin-bottom:4px}
.seo-preview .sp-title{color:#60a5fa;font-size:1rem;font-weight:600;margin-bottom:4px;cursor:pointer}
.seo-preview .sp-title:hover{text-decoration:underline}
.seo-preview .sp-desc{color:#9ca3af;font-size:.82rem;line-height:1.5}
.ai-gen-box{background:linear-gradient(135deg,rgba(124,58,237,.1),rgba(232,67,147,.08));
border:1px solid rgba(124,58,237,.3);border-radius:12px;padding:20px;margin-bottom:24px}
</style>
@endpush
@section('content')
<div class="row g-4">
{{-- LEFT: AI Üretici --}}
<div class="col-12">
<div class="ai-gen-box">
<div class="d-flex align-items-center gap-2 mb-3">
<i class="bi bi-stars" style="color:#7c3aed;font-size:1.2rem"></i>
<strong style="color:var(--text)">AI Blog Yazısı Üretici</strong>
<span style="color:var(--text2);font-size:.8rem"> DeepSeek ile otomatik SEO içeriği üret</span>
</div>
<div class="d-flex gap-2 align-items-end flex-wrap">
<div style="flex:1;min-width:200px">
<label class="form-label">Anime Seç</label>
<select id="ai-anime-select" class="form-select form-select-sm">
<option value=""> Anime seç </option>
@foreach($animes as $a)
<option value="{{ $a->id }}" {{ (isset($blog->anime_id) && $blog->anime_id == $a->id) ? 'selected' : '' }}>
{{ $a->title }}
</option>
@endforeach
</select>
</div>
<button type="button" onclick="generateAiBlog()" id="ai-gen-btn"
class="btn btn-sm" style="background:linear-gradient(135deg,#7c3aed,var(--accent));color:#fff;border:none;white-space:nowrap">
<i class="bi bi-magic me-1"></i>AI ile Üret
</button>
<div id="ai-gen-status" style="font-size:.8rem;color:var(--text2)"></div>
</div>
</div>
</div>
{{-- FORM --}}
<div class="col-12">
<form action="{{ isset($blog->id) ? route('admin.blog.update', $blog) : route('admin.blog.store') }}"
method="POST">
@csrf
@if(isset($blog->id)) @method('PUT') @endif
<div class="row g-4">
<div class="col-lg-8">
{{-- Başlık --}}
<div class="mb-3">
<label class="form-label">Başlık *</label>
<input type="text" name="title" id="f-title" class="form-control"
value="{{ old('title', $blog->title ?? '') }}" required maxlength="255"
oninput="updateCharCount(this,'cc-title',60)">
<div class="char-counter" id="cc-title">{{ mb_strlen(old('title', $blog->title ?? '')) }}/60</div>
</div>
{{-- Excerpt --}}
<div class="mb-3">
<label class="form-label">Özet (Excerpt)</label>
<textarea name="excerpt" id="f-excerpt" class="form-control" rows="3"
maxlength="300" oninput="updateCharCount(this,'cc-excerpt',160)">{{ old('excerpt', $blog->excerpt ?? '') }}</textarea>
<div class="char-counter" id="cc-excerpt">{{ mb_strlen(old('excerpt', $blog->excerpt ?? '')) }}/160</div>
</div>
{{-- Content --}}
<div class="mb-3">
<label class="form-label">İçerik (HTML)</label>
<textarea name="content" id="f-content" class="form-control"
rows="22" style="font-family:monospace;font-size:.82rem">{{ old('content', $blog->content ?? '') }}</textarea>
<div class="form-text">HTML etiketleri desteklenir. AI içeriği doğrudan buraya eklenir.</div>
</div>
</div>
<div class="col-lg-4">
{{-- SEO Önizleme --}}
<div class="mb-3">
<label class="form-label">Google Önizleme</label>
<div class="seo-preview">
<div class="sp-url" id="sp-url">animexe.com/blog/...</div>
<div class="sp-title" id="sp-title">{{ old('title', $blog->title ?? 'Başlık giriniz') }}</div>
<div class="sp-desc" id="sp-desc">{{ old('meta_description', $blog->meta_description ?? 'Açıklama giriniz') }}</div>
</div>
</div>
{{-- Yayın Durumu --}}
<div class="mb-3">
<label class="form-label">Durum</label>
<select name="status" class="form-select">
<option value="draft" {{ (old('status', $blog->status ?? '') === 'draft') ? 'selected' : '' }}>Taslak</option>
<option value="published" {{ (old('status', $blog->status ?? '') === 'published') ? 'selected' : '' }}>Yayında</option>
</select>
</div>
{{-- Anime --}}
<div class="mb-3">
<label class="form-label">İlgili Anime</label>
<select name="anime_id" id="f-anime" class="form-select">
<option value=""> Seçiniz </option>
@foreach($animes as $a)
<option value="{{ $a->id }}" {{ (old('anime_id', $blog->anime_id ?? '') == $a->id) ? 'selected' : '' }}>
{{ $a->title }}
</option>
@endforeach
</select>
</div>
{{-- Kapak Görseli --}}
<div class="mb-3">
<label class="form-label">Kapak Görseli URL</label>
<input type="url" name="cover_image" class="form-control"
value="{{ old('cover_image', $blog->cover_image ?? '') }}" placeholder="https://...">
</div>
{{-- Odak Kelime --}}
<div class="mb-3">
<label class="form-label">Odak Anahtar Kelime</label>
<input type="text" name="focus_keyword" id="f-focus" class="form-control"
value="{{ old('focus_keyword', $blog->focus_keyword ?? '') }}" maxlength="255">
</div>
{{-- Meta Description --}}
<div class="mb-3">
<label class="form-label">Meta Description</label>
<textarea name="meta_description" id="f-metadesc" class="form-control" rows="3"
maxlength="200" oninput="updateCharCount(this,'cc-metadesc',160);updateSeoPreview()">{{ old('meta_description', $blog->meta_description ?? '') }}</textarea>
<div class="char-counter" id="cc-metadesc">{{ mb_strlen(old('meta_description', $blog->meta_description ?? '')) }}/160</div>
</div>
{{-- Meta Keywords --}}
<div class="mb-3">
<label class="form-label">Meta Keywords</label>
<input type="text" name="meta_keywords" class="form-control"
value="{{ old('meta_keywords', $blog->meta_keywords ?? '') }}" placeholder="kelime1, kelime2, ...">
</div>
{{-- Okuma Süresi --}}
<div class="mb-3">
<label class="form-label">Okuma Süresi (dakika)</label>
<input type="number" name="reading_time" class="form-control" min="1" max="60"
value="{{ old('reading_time', $blog->reading_time ?? 5) }}">
</div>
<button type="submit" class="btn btn-primary w-100">
<i class="bi bi-check-lg me-1"></i>Kaydet
</button>
<a href="{{ route('admin.blog.index') }}" class="btn btn-outline-secondary w-100 mt-2">İptal</a>
</div>
</div>
</form>
</div>
</div>
@endsection
@push('scripts')
<script>
function updateCharCount(el, counterId, warn) {
const len = el.value.length;
const el2 = document.getElementById(counterId);
if (!el2) return;
el2.textContent = len + '/' + warn;
el2.className = 'char-counter' + (len > warn * 1.1 ? ' danger' : len > warn * .9 ? ' warn' : '');
}
function updateSeoPreview() {
const title = document.getElementById('f-title')?.value || '';
const desc = document.getElementById('f-metadesc')?.value || document.getElementById('f-excerpt')?.value || '';
document.getElementById('sp-title').textContent = title || 'Başlık giriniz';
document.getElementById('sp-desc').textContent = desc || 'Açıklama giriniz';
}
document.getElementById('f-title')?.addEventListener('input', updateSeoPreview);
document.getElementById('f-excerpt')?.addEventListener('input', updateSeoPreview);
updateSeoPreview();
async function generateAiBlog() {
const animeId = document.getElementById('ai-anime-select')?.value;
if (!animeId) { alert('Lütfen bir anime seçin.'); return; }
const btn = document.getElementById('ai-gen-btn');
const status = document.getElementById('ai-gen-status');
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Üretiliyor...';
status.textContent = 'DeepSeek AI çalışıyor, lütfen bekleyin (30-60 sn)...';
try {
const csrfToken = document.querySelector('meta[name=csrf-token]')?.content
|| document.querySelector('input[name=_token]')?.value || '';
const res = await fetch('{{ route("admin.blog.generate-ai") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify({ anime_id: animeId })
});
const data = await res.json();
if (!res.ok || data.error) {
status.textContent = 'Hata: ' + (data.error || 'Bilinmeyen hata');
status.style.color = '#ef4444';
return;
}
// Form alanlarını doldur
document.getElementById('f-title').value = data.title || '';
document.getElementById('f-excerpt').value = data.excerpt || '';
document.getElementById('f-content').value = data.content || '';
document.getElementById('f-focus').value = data.focus_keyword || '';
document.getElementById('f-metadesc').value = data.meta_description || '';
// Anime select'i de güncelle
const animeSelect = document.getElementById('f-anime');
if (animeSelect) animeSelect.value = animeId;
// Char count'ları güncelle
['f-title','f-excerpt','f-metadesc'].forEach(id => {
const el = document.getElementById(id);
if (el) el.dispatchEvent(new Event('input'));
});
updateSeoPreview();
status.textContent = '✓ İçerik başarıyla üretildi! Kontrol edip kaydedin.';
status.style.color = '#4ade80';
} catch(e) {
status.textContent = 'Bağlantı hatası: ' + e.message;
status.style.color = '#ef4444';
} finally {
btn.disabled = false;
btn.innerHTML = '<i class="bi bi-magic me-1"></i>AI ile Üret';
}
}
</script>
@endpush