Initial commit: Animexe Laravel platform
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,462 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title','AI Asistan — Animexe')
|
||||
@push('styles')
|
||||
<style>
|
||||
.ai-hero{
|
||||
padding:52px 24px 28px;max-width:900px;margin:0 auto;text-align:center;
|
||||
}
|
||||
.ai-hero-icon{
|
||||
width:80px;height:80px;border-radius:50%;margin:0 auto 20px;
|
||||
background:linear-gradient(135deg,var(--accent3),var(--accent));
|
||||
display:flex;align-items:center;justify-content:center;font-size:2.2rem;color:#fff;
|
||||
box-shadow:0 0 48px rgba(184,77,255,.45),0 0 80px rgba(255,45,125,.2);
|
||||
animation:ai-glow 3s ease-in-out infinite;
|
||||
}
|
||||
@keyframes ai-glow{
|
||||
0%,100%{box-shadow:0 0 48px rgba(184,77,255,.45),0 0 80px rgba(255,45,125,.2)}
|
||||
50%{box-shadow:0 0 64px rgba(184,77,255,.65),0 0 100px rgba(255,45,125,.35)}
|
||||
}
|
||||
.ai-hero h1{
|
||||
font-family:var(--font-display);font-size:clamp(1.6rem,4vw,2.5rem);font-weight:800;
|
||||
background:linear-gradient(120deg,#fff 0%,var(--accent3) 40%,var(--accent) 100%);
|
||||
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
.ai-hero p{color:var(--text2);font-size:1rem;max-width:520px;margin:0 auto 32px;line-height:1.7}
|
||||
|
||||
.ai-tabs{
|
||||
display:flex;gap:8px;justify-content:center;flex-wrap:wrap;margin-bottom:32px;
|
||||
}
|
||||
.ai-tab{
|
||||
padding:10px 22px;border-radius:999px;font-size:.88rem;font-weight:700;cursor:pointer;
|
||||
background:var(--surface);border:1px solid var(--border);color:var(--text2);
|
||||
transition:all .18s;
|
||||
}
|
||||
.ai-tab.on,.ai-tab:hover{
|
||||
background:linear-gradient(135deg,rgba(184,77,255,.18),rgba(255,45,125,.1));
|
||||
border-color:var(--accent3);color:var(--accent3);
|
||||
box-shadow:0 0 20px rgba(184,77,255,.2);
|
||||
}
|
||||
|
||||
.ai-section{max-width:900px;margin:0 auto;padding:0 24px 48px}
|
||||
|
||||
/* Öneri kartı */
|
||||
.ai-box{
|
||||
background:linear-gradient(145deg,rgba(17,17,31,.95),rgba(10,10,20,.98));
|
||||
border:1px solid rgba(184,77,255,.2);border-radius:18px;padding:28px;
|
||||
box-shadow:0 8px 40px rgba(0,0,0,.35),0 0 40px rgba(184,77,255,.05);
|
||||
}
|
||||
.ai-box-title{
|
||||
font-family:var(--font-display);font-size:.85rem;letter-spacing:.12em;
|
||||
text-transform:uppercase;color:var(--accent3);font-weight:700;
|
||||
display:flex;align-items:center;gap:10px;margin-bottom:20px;
|
||||
}
|
||||
.ai-box-title i{font-size:1.1rem}
|
||||
|
||||
/* Ruh hali chips */
|
||||
.mood-grid{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:20px}
|
||||
.mood-chip{
|
||||
padding:8px 16px;border-radius:999px;font-size:.82rem;font-weight:600;cursor:pointer;
|
||||
background:rgba(17,17,31,.8);border:1px solid var(--border);color:var(--text2);
|
||||
transition:all .16s;display:flex;align-items:center;gap:6px;
|
||||
}
|
||||
.mood-chip.on,.mood-chip:hover{
|
||||
background:rgba(184,77,255,.14);border-color:var(--accent3);color:var(--accent3);
|
||||
box-shadow:0 0 16px rgba(184,77,255,.2);
|
||||
}
|
||||
|
||||
/* Tür chips */
|
||||
.genre-wrap{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:20px}
|
||||
|
||||
/* Tip toggle */
|
||||
.type-row{display:flex;gap:8px;margin-bottom:24px}
|
||||
.type-btn{
|
||||
flex:1;padding:10px;border-radius:10px;border:1px solid var(--border);
|
||||
background:var(--surface);color:var(--text2);font-size:.84rem;font-weight:700;
|
||||
cursor:pointer;transition:all .16s;text-align:center;
|
||||
}
|
||||
.type-btn.on{
|
||||
background:rgba(0,245,255,.1);border-color:var(--accent2);color:var(--accent2);
|
||||
box-shadow:0 0 16px rgba(0,245,255,.12);
|
||||
}
|
||||
|
||||
.ai-btn{
|
||||
width:100%;padding:14px;border-radius:12px;border:none;cursor:pointer;
|
||||
background:linear-gradient(135deg,var(--accent3),var(--accent));color:#fff;
|
||||
font-size:.95rem;font-weight:800;letter-spacing:.04em;
|
||||
transition:transform .16s,box-shadow .18s;
|
||||
box-shadow:0 0 28px rgba(184,77,255,.3),0 4px 16px rgba(255,45,125,.2);
|
||||
display:flex;align-items:center;justify-content:center;gap:10px;
|
||||
}
|
||||
.ai-btn:hover{transform:translateY(-1px);box-shadow:0 0 40px rgba(184,77,255,.45)}
|
||||
.ai-btn:disabled{opacity:.55;cursor:not-allowed;transform:none}
|
||||
|
||||
/* Loader */
|
||||
.ai-loader{display:none;justify-content:center;align-items:center;gap:6px;padding:28px}
|
||||
.ai-loader.on{display:flex}
|
||||
.al-dot{width:10px;height:10px;border-radius:50%;background:var(--accent3);animation:al-b .9s ease-in-out infinite}
|
||||
.al-dot:nth-child(2){animation-delay:.18s;background:var(--accent)}
|
||||
.al-dot:nth-child(3){animation-delay:.36s;background:var(--accent2)}
|
||||
@keyframes al-b{0%,80%,100%{transform:scale(.5);opacity:.4}40%{transform:scale(1);opacity:1}}
|
||||
|
||||
/* Sonuç grid */
|
||||
.ai-results{margin-top:24px;display:none}
|
||||
.ai-results.on{display:block}
|
||||
.ai-res-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:16px;margin-top:16px}
|
||||
.ai-res-card{
|
||||
background:var(--surface);border:1px solid rgba(0,245,255,.1);border-radius:14px;
|
||||
overflow:hidden;cursor:pointer;transition:all .2s;
|
||||
}
|
||||
.ai-res-card:hover{transform:translateY(-5px);border-color:rgba(255,45,125,.4);box-shadow:0 12px 36px rgba(0,0,0,.4),0 0 28px rgba(255,45,125,.1)}
|
||||
.ai-res-poster{position:relative;aspect-ratio:2/3;background:var(--surface2);overflow:hidden}
|
||||
.ai-res-poster img{width:100%;height:100%;object-fit:cover;transition:transform .28s}
|
||||
.ai-res-card:hover .ai-res-poster img{transform:scale(1.06)}
|
||||
.ai-res-poster-ph{width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:var(--text3);font-size:2rem}
|
||||
.ai-res-reason{
|
||||
position:absolute;bottom:0;left:0;right:0;padding:8px;
|
||||
background:linear-gradient(to top,rgba(0,0,0,.88),transparent);
|
||||
font-size:.65rem;color:rgba(255,255,255,.8);line-height:1.35;
|
||||
}
|
||||
.ai-res-body{padding:9px 10px}
|
||||
.ai-res-title{font-size:.8rem;font-weight:700;color:var(--text);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
|
||||
.ai-res-meta{font-size:.7rem;color:var(--text3);margin-top:3px}
|
||||
|
||||
/* Natural search */
|
||||
.ai-search-wrap{position:relative}
|
||||
.ai-search-wrap input{
|
||||
width:100%;background:rgba(255,255,255,.05);border:1px solid rgba(184,77,255,.3);
|
||||
border-radius:12px;padding:14px 52px 14px 18px;color:var(--text);font-size:.9rem;
|
||||
font-family:inherit;outline:none;transition:all .18s;
|
||||
}
|
||||
.ai-search-wrap input:focus{
|
||||
border-color:var(--accent3);background:rgba(184,77,255,.06);
|
||||
box-shadow:0 0 0 3px rgba(184,77,255,.15),0 0 32px rgba(184,77,255,.1);
|
||||
}
|
||||
.ai-search-wrap input::placeholder{color:var(--text3)}
|
||||
.ai-search-btn{
|
||||
position:absolute;right:10px;top:50%;transform:translateY(-50%);
|
||||
width:36px;height:36px;border-radius:9px;border:none;cursor:pointer;
|
||||
background:linear-gradient(135deg,var(--accent3),var(--accent));color:#fff;font-size:.9rem;
|
||||
display:flex;align-items:center;justify-content:center;transition:transform .14s;
|
||||
}
|
||||
.ai-search-btn:hover{transform:translateY(-50%) scale(1.08)}
|
||||
.ai-search-hints{display:flex;flex-wrap:wrap;gap:6px;margin-top:12px}
|
||||
.ai-hint{
|
||||
padding:6px 13px;border-radius:999px;font-size:.75rem;font-weight:600;cursor:pointer;
|
||||
background:rgba(0,245,255,.06);border:1px solid rgba(0,245,255,.2);color:var(--accent2);
|
||||
transition:all .14s;
|
||||
}
|
||||
.ai-hint:hover{background:rgba(0,245,255,.12);box-shadow:0 0 12px rgba(0,245,255,.15)}
|
||||
|
||||
.ai-empty{text-align:center;padding:32px;color:var(--text3);font-size:.9rem}
|
||||
.ai-error{padding:14px 18px;border-radius:10px;background:rgba(255,60,90,.08);border:1px solid rgba(255,60,90,.25);color:#ff8a9a;font-size:.85rem;margin-top:16px;display:none}
|
||||
.ai-error.on{display:block}
|
||||
|
||||
@media(max-width:600px){
|
||||
.ai-hero{padding:36px 16px 20px}
|
||||
.ai-hero p{font-size:.9rem}
|
||||
.ai-section{padding:0 14px 40px}
|
||||
.ai-box{padding:18px 14px}
|
||||
.ai-res-grid{grid-template-columns:repeat(3,1fr);gap:10px}
|
||||
.ai-tabs{gap:5px}
|
||||
.ai-tab{padding:8px 14px;font-size:.82rem}
|
||||
.type-row{gap:6px}
|
||||
.mood-chip{font-size:.78rem;padding:6px 12px}
|
||||
.ai-search-wrap input{font-size:.85rem;padding:12px 46px 12px 14px}
|
||||
}
|
||||
@media(max-width:380px){
|
||||
.ai-res-grid{grid-template-columns:repeat(2,1fr)}
|
||||
.ai-hero h1{font-size:1.4rem}
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="ai-hero">
|
||||
<div class="ai-hero-icon"><i class="bi bi-stars"></i></div>
|
||||
<h1>Animexe AI Asistan</h1>
|
||||
<p>Yapay zeka destekli anime keşfi. Ruh haline göre öneri al, doğal dille ara veya sağ alttaki balondan sohbet et.</p>
|
||||
|
||||
@guest
|
||||
<div style="background:rgba(255,45,125,.08);border:1px solid rgba(255,45,125,.25);border-radius:14px;padding:20px 24px;text-align:center;max-width:480px;margin:20px auto 0">
|
||||
<i class="bi bi-lock" style="font-size:1.8rem;color:var(--accent);display:block;margin-bottom:10px"></i>
|
||||
<p style="color:var(--text2);font-size:.9rem;margin-bottom:16px">AI özelliklerini kullanmak için ücretsiz hesap oluştur veya giriş yap.</p>
|
||||
<a href="{{ route('frontend.register') }}" style="display:inline-block;padding:10px 24px;background:var(--accent);border-radius:20px;color:#fff;font-weight:700;text-decoration:none;margin-right:8px">Ücretsiz Kayıt Ol</a>
|
||||
<a href="{{ route('frontend.login') }}" style="display:inline-block;padding:10px 24px;background:#21262d;border-radius:20px;color:var(--text2);font-weight:600;text-decoration:none">Giriş Yap</a>
|
||||
</div>
|
||||
@endguest
|
||||
|
||||
<div class="ai-tabs" @guest style="margin-top:20px;opacity:.5;pointer-events:none" @endguest>
|
||||
<button class="ai-tab on" onclick="switchAiTab('recommend',this)"><i class="bi bi-magic"></i> Kişisel Öneri</button>
|
||||
<button class="ai-tab" onclick="switchAiTab('search',this)"><i class="bi bi-search-heart"></i> Doğal Dil Ara</button>
|
||||
<button class="ai-tab" onclick="switchAiTab('platform',this)"><i class="bi bi-question-circle"></i> Site Yardımı</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ai-section">
|
||||
|
||||
{{-- ── TAB 1: Kişisel Öneri ─────────────────────────────────── --}}
|
||||
<div id="tab-recommend">
|
||||
<div class="ai-box">
|
||||
<div class="ai-box-title"><i class="bi bi-emoji-smile"></i> Nasıl bir ruh halindeydin?</div>
|
||||
<div class="mood-grid">
|
||||
@foreach([
|
||||
['😤','Aksiyona dolu','action'],['😢','Duygusal ağlatıcı','emotional'],
|
||||
['😂','Komik ve eğlenceli','comedy'],['😨','Gerilim/Korku','thriller'],
|
||||
['🌸','Romantik','romance'],['🤯','Akıl oyunları','mindgame'],
|
||||
['⚔️','Fantezi macera','fantasy'],['🤖','Sci-Fi / Mecha','scifi'],
|
||||
['🏫','Okul / Slice of life','school'],['💪','Motivasyonel','motivational'],
|
||||
] as $m)
|
||||
<button class="mood-chip" data-mood="{{ $m[2] }}" onclick="toggleMood(this,'{{ addslashes($m[0].' '.$m[1]) }}')">
|
||||
{{ $m[0] }} {{ $m[1] }}
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div class="ai-box-title" style="margin-top:4px"><i class="bi bi-tags"></i> Tür tercihleri (opsiyonel)</div>
|
||||
<div class="genre-wrap" id="genre-wrap">
|
||||
@foreach($genres as $g)
|
||||
<button class="genre-chip" data-genre="{{ $g->name }}" onclick="this.classList.toggle('on')">{{ $g->name }}</button>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div class="ai-box-title" style="margin-top:4px"><i class="bi bi-collection-play"></i> İçerik tipi</div>
|
||||
<div class="type-row" id="type-row">
|
||||
<button class="type-btn on" data-type="" onclick="selectType(this)">Hepsi</button>
|
||||
<button class="type-btn" data-type="series" onclick="selectType(this)">Dizi</button>
|
||||
<button class="type-btn" data-type="movie" onclick="selectType(this)">Film</button>
|
||||
</div>
|
||||
|
||||
<button class="ai-btn" id="rec-btn" onclick="getRecommendations()">
|
||||
<i class="bi bi-magic"></i> Bana Özel Öneri Al
|
||||
</button>
|
||||
<div class="ai-error" id="rec-error"></div>
|
||||
</div>
|
||||
|
||||
<div class="ai-loader" id="rec-loader">
|
||||
<div class="al-dot"></div><div class="al-dot"></div><div class="al-dot"></div>
|
||||
<span style="color:var(--text3);font-size:.85rem;margin-left:6px">AI düşünüyor...</span>
|
||||
</div>
|
||||
|
||||
<div class="ai-results" id="rec-results">
|
||||
<div style="display:flex;align-items:center;gap:10px;margin-bottom:4px">
|
||||
<span style="font-family:var(--font-display);font-size:.82rem;letter-spacing:.1em;text-transform:uppercase;color:var(--accent3)"><i class="bi bi-stars" style="margin-right:6px"></i>AI Önerileri</span>
|
||||
</div>
|
||||
<div class="ai-res-grid" id="rec-grid"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ── TAB 3: Platform Yardımı ─────────────────────────────── --}}
|
||||
<div id="tab-platform" style="display:none">
|
||||
<div class="ai-box">
|
||||
<div class="ai-box-title"><i class="bi bi-question-circle"></i> Animexe Hakkında Sık Sorulanlar</div>
|
||||
<div style="display:grid;gap:10px">
|
||||
@foreach([
|
||||
['Kayıt olmak ücretsiz mi?','Evet! Animexe\'ye kayıt olmak tamamen ücretsizdir. E-posta adresinle saniyeler içinde hesap oluşturabilirsin.'],
|
||||
['Premium üyelik ne sağlar?','Premium üyelik ile reklamsız izleme, 1080p HD kalite ve yeni bölümlere erken erişim imkanı kazanırsın.'],
|
||||
['Altyazı ve dublaj var mı?','Evet, çoğu animede Türkçe altyazı bulunur. Bir kısım animede Türkçe dublaj da mevcuttur.'],
|
||||
['Hangi cihazlarda çalışır?','Bilgisayar, tablet ve telefon tarayıcısında sorunsuz çalışır. Özel bir uygulama indirmene gerek yok.'],
|
||||
['Şifremi unuttum, ne yapmalıyım?','Giriş sayfasındaki "Şifremi Unuttum" linkine tıklayarak e-postanla şifre sıfırlama bağlantısı alabilirsin.'],
|
||||
] as [$q, $a])
|
||||
<details style="background:rgba(255,255,255,.03);border:1px solid rgba(184,77,255,.15);border-radius:10px;overflow:hidden">
|
||||
<summary style="padding:13px 16px;cursor:pointer;font-size:.86rem;font-weight:600;color:var(--text);list-style:none;display:flex;align-items:center;justify-content:space-between">
|
||||
{{ $q }}
|
||||
<i class="bi bi-chevron-down" style="font-size:.75rem;color:var(--accent3);flex-shrink:0;transition:transform .2s"></i>
|
||||
</summary>
|
||||
<p style="padding:0 16px 14px;margin:0;font-size:.84rem;color:var(--text2);line-height:1.65">{{ $a }}</p>
|
||||
</details>
|
||||
@endforeach
|
||||
</div>
|
||||
<div style="margin-top:20px;padding:14px;background:rgba(184,77,255,.07);border:1px solid rgba(184,77,255,.2);border-radius:12px;text-align:center">
|
||||
<p style="margin:0 0 12px;color:var(--text2);font-size:.85rem">Cevabını bulamadın mı? AI asistana sor!</p>
|
||||
<button class="ai-btn" style="width:auto;padding:10px 24px;display:inline-flex" onclick="openAiWithQuestion()">
|
||||
<i class="bi bi-chat-dots-fill"></i> AI\'a Sor
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ── TAB 2: Doğal Dil Arama ─────────────────────────────── --}}
|
||||
<div id="tab-search" style="display:none">
|
||||
<div class="ai-box">
|
||||
<div class="ai-box-title"><i class="bi bi-search-heart"></i> Ne aramak istiyorsun?</div>
|
||||
<div class="ai-search-wrap">
|
||||
<input type="text" id="ai-search-inp" placeholder="Ör: ağlatan romantik okul animesi, 2023'te çıkmış aksiyon dizisi..."
|
||||
onkeydown="if(event.key==='Enter') aiNaturalSearch()">
|
||||
<button class="ai-search-btn" onclick="aiNaturalSearch()"><i class="bi bi-send-fill"></i></button>
|
||||
</div>
|
||||
<div class="ai-search-hints">
|
||||
@foreach(['Ağlatan romantik anime','İsekai macera dizisi','Kısa 12 bölüm aksiyon','Dövüş sanatları anime','Distopik sci-fi film','Komedi okul dizisi'] as $h)
|
||||
<button class="ai-hint" onclick="document.getElementById('ai-search-inp').value=this.textContent;aiNaturalSearch()">{{ $h }}</button>
|
||||
@endforeach
|
||||
</div>
|
||||
<div class="ai-error" id="search-error"></div>
|
||||
</div>
|
||||
|
||||
<div class="ai-loader" id="search-loader">
|
||||
<div class="al-dot"></div><div class="al-dot"></div><div class="al-dot"></div>
|
||||
<span style="color:var(--text3);font-size:.85rem;margin-left:6px">AI arıyor...</span>
|
||||
</div>
|
||||
|
||||
<div class="ai-results" id="search-results">
|
||||
<div style="display:flex;align-items:center;gap:10px;margin-bottom:4px">
|
||||
<span style="font-family:var(--font-display);font-size:.82rem;letter-spacing:.1em;text-transform:uppercase;color:var(--accent2)"><i class="bi bi-lightning-fill" style="margin-right:6px"></i>AI Arama Sonuçları</span>
|
||||
</div>
|
||||
<div class="ai-res-grid" id="search-grid"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
const CSRF = document.querySelector('meta[name=csrf-token]').content;
|
||||
|
||||
// ── Tab yönetimi ──────────────────────────────────────────────────────────────
|
||||
function switchAiTab(tab, btn){
|
||||
document.querySelectorAll('.ai-tab').forEach(b=>b.classList.remove('on'));
|
||||
btn.classList.add('on');
|
||||
document.getElementById('tab-recommend').style.display = tab==='recommend' ? '' : 'none';
|
||||
document.getElementById('tab-search').style.display = tab==='search' ? '' : 'none';
|
||||
document.getElementById('tab-platform').style.display = tab==='platform' ? '' : 'none';
|
||||
}
|
||||
|
||||
function openAiWithQuestion(){
|
||||
if(typeof window.toggleAiPanel === 'function'){
|
||||
window.toggleAiPanel();
|
||||
setTimeout(()=>{
|
||||
const inp = document.getElementById('ai-inp');
|
||||
if(inp){ inp.focus(); inp.placeholder='Site hakkında soru sor...'; }
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Ruh hali seçimi ───────────────────────────────────────────────────────────
|
||||
let selectedMoods = [];
|
||||
function toggleMood(btn, label){
|
||||
btn.classList.toggle('on');
|
||||
if(btn.classList.contains('on')){
|
||||
selectedMoods.push(label);
|
||||
} else {
|
||||
selectedMoods = selectedMoods.filter(m=>m!==label);
|
||||
}
|
||||
}
|
||||
|
||||
function selectType(btn){
|
||||
document.querySelectorAll('#type-row .type-btn').forEach(b=>b.classList.remove('on'));
|
||||
btn.classList.add('on');
|
||||
}
|
||||
|
||||
// ── Öneri al ─────────────────────────────────────────────────────────────────
|
||||
async function getRecommendations(){
|
||||
const btn = document.getElementById('rec-btn');
|
||||
const loader = document.getElementById('rec-loader');
|
||||
const results = document.getElementById('rec-results');
|
||||
const errEl = document.getElementById('rec-error');
|
||||
|
||||
const mood = selectedMoods.join(', ');
|
||||
const genres = [...document.querySelectorAll('#genre-wrap .genre-chip.on')].map(c=>c.dataset.genre);
|
||||
const type = document.querySelector('#type-row .type-btn.on')?.dataset.type || '';
|
||||
|
||||
btn.disabled = true;
|
||||
loader.classList.add('on');
|
||||
results.classList.remove('on');
|
||||
errEl.classList.remove('on');
|
||||
|
||||
try{
|
||||
const res = await fetch('{{ route("ai.recommend") }}',{
|
||||
method:'POST',
|
||||
headers:{'Content-Type':'application/json','X-CSRF-TOKEN':CSRF},
|
||||
body: JSON.stringify({ mood, genres, type })
|
||||
});
|
||||
const data = await res.json();
|
||||
loader.classList.remove('on');
|
||||
|
||||
if(data.error){ errEl.textContent=data.error; errEl.classList.add('on'); }
|
||||
else { renderRecGrid(data.recommendations || [], 'rec-grid', true); results.classList.add('on'); }
|
||||
}catch(e){
|
||||
loader.classList.remove('on');
|
||||
errEl.textContent = 'Bağlantı hatası, tekrar dene.';
|
||||
errEl.classList.add('on');
|
||||
}
|
||||
btn.disabled = false;
|
||||
}
|
||||
|
||||
// ── Doğal dil arama ───────────────────────────────────────────────────────────
|
||||
async function aiNaturalSearch(){
|
||||
const query = document.getElementById('ai-search-inp').value.trim();
|
||||
if(!query) return;
|
||||
|
||||
const loader = document.getElementById('search-loader');
|
||||
const results = document.getElementById('search-results');
|
||||
const errEl = document.getElementById('search-error');
|
||||
|
||||
loader.classList.add('on');
|
||||
results.classList.remove('on');
|
||||
errEl.classList.remove('on');
|
||||
|
||||
try{
|
||||
const res = await fetch('{{ route("ai.search") }}',{
|
||||
method:'POST',
|
||||
headers:{'Content-Type':'application/json','X-CSRF-TOKEN':CSRF},
|
||||
body: JSON.stringify({ query })
|
||||
});
|
||||
const data = await res.json();
|
||||
loader.classList.remove('on');
|
||||
|
||||
if(data.error){ errEl.textContent=data.error; errEl.classList.add('on'); }
|
||||
else if(!data.results || !data.results.length){
|
||||
errEl.textContent = 'Sonuç bulunamadı. Farklı bir şey dene!';
|
||||
errEl.classList.add('on');
|
||||
} else {
|
||||
renderRecGrid(data.results, 'search-grid', false);
|
||||
results.classList.add('on');
|
||||
}
|
||||
}catch(e){
|
||||
loader.classList.remove('on');
|
||||
errEl.textContent = 'Bağlantı hatası, tekrar dene.';
|
||||
errEl.classList.add('on');
|
||||
}
|
||||
}
|
||||
|
||||
// ── Kart render ───────────────────────────────────────────────────────────────
|
||||
function renderRecGrid(items, gridId, showReason){
|
||||
const grid = document.getElementById(gridId);
|
||||
grid.innerHTML = '';
|
||||
if(!items.length){
|
||||
grid.innerHTML = '<div class="ai-empty">Sonuç bulunamadı.</div>';
|
||||
return;
|
||||
}
|
||||
items.forEach(a=>{
|
||||
const detailUrl = '/anime/'+a.slug;
|
||||
const watchUrl = '/watch/'+a.slug+'/1/1';
|
||||
const typeLabel = a.type==='movie' ? '🎬 Film' : (a.type==='ova' ? 'OVA' : '📺 Dizi');
|
||||
const ratingHtml = a.rating ? `<span style="color:#f59e0b;font-weight:700">★${parseFloat(a.rating).toFixed(1)}</span>` : '';
|
||||
const epHtml = a.episode_count ? `<span>${a.episode_count} bölüm</span>` : '';
|
||||
grid.innerHTML += `
|
||||
<div class="ai-res-card">
|
||||
<div class="ai-res-poster">
|
||||
${a.cover
|
||||
? `<img src="${esc(a.cover)}" alt="${esc(a.title)}" loading="lazy">`
|
||||
: `<div class="ai-res-poster-ph"><i class="bi bi-image"></i></div>`}
|
||||
<div style="position:absolute;top:6px;left:6px;background:rgba(0,0,0,.72);backdrop-filter:blur(4px);border-radius:5px;padding:2px 7px;font-size:.65rem;font-weight:700;color:#fff">${typeLabel}</div>
|
||||
${showReason && a.reason ? `<div class="ai-res-reason">${esc(a.reason)}</div>` : ''}
|
||||
</div>
|
||||
<div class="ai-res-body">
|
||||
<div class="ai-res-title">${esc(a.title)}</div>
|
||||
<div class="ai-res-meta" style="display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:4px">
|
||||
${ratingHtml}${epHtml}
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;gap:5px;padding:0 9px 9px">
|
||||
<a href="${esc(watchUrl)}" style="flex:1;padding:6px 0;background:linear-gradient(135deg,var(--accent3),var(--accent));border-radius:8px;color:#fff;font-size:.72rem;font-weight:700;text-align:center;text-decoration:none;display:flex;align-items:center;justify-content:center;gap:3px"><i class="bi bi-play-fill"></i>İzle</a>
|
||||
<a href="${esc(detailUrl)}" style="flex:1;padding:6px 0;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1);border-radius:8px;color:var(--text2);font-size:.72rem;font-weight:700;text-align:center;text-decoration:none;display:flex;align-items:center;justify-content:center;gap:3px"><i class="bi bi-info-circle"></i>Detay</a>
|
||||
</div>
|
||||
</div>`;
|
||||
});
|
||||
}
|
||||
|
||||
function esc(s){ return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); }
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,213 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Anime İsteği — Animexe')
|
||||
|
||||
@push('styles')
|
||||
<style>
|
||||
.req-hero{padding:60px 24px 32px;text-align:center;max-width:700px;margin:0 auto}
|
||||
.req-hero h1{font-size:2rem;font-weight:800;color:var(--text);margin-bottom:8px}
|
||||
.req-hero p{color:var(--text2);font-size:.95rem}
|
||||
|
||||
.req-wrap{max-width:900px;margin:0 auto;padding:0 20px 60px}
|
||||
|
||||
.req-form-card{background:var(--surface);border:1px solid var(--border);border-radius:16px;padding:24px;margin-bottom:32px}
|
||||
.req-form-card h2{font-size:1rem;font-weight:700;color:var(--text);margin-bottom:18px;display:flex;align-items:center;gap:8px}
|
||||
|
||||
.rf-field{margin-bottom:16px}
|
||||
.rf-label{display:block;font-size:.8rem;color:var(--text2);margin-bottom:6px;font-weight:500}
|
||||
.rf-input{width:100%;background:#0a0a14;border:1px solid var(--border);border-radius:8px;padding:10px 14px;color:var(--text);font-size:.9rem;transition:border-color .2s}
|
||||
.rf-input:focus{outline:none;border-color:var(--accent)}
|
||||
.rf-textarea{resize:vertical;min-height:80px}
|
||||
.rf-submit{display:flex;align-items:center;justify-content:center;gap:8px;padding:11px 24px;background:var(--accent);border:none;border-radius:20px;color:#fff;font-size:.9rem;font-weight:600;cursor:pointer;transition:opacity .2s}
|
||||
.rf-submit:hover{opacity:.85}
|
||||
|
||||
.req-list-card{background:var(--surface);border:1px solid var(--border);border-radius:16px;overflow:hidden}
|
||||
.req-list-head{padding:16px 20px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between}
|
||||
.req-list-head h2{font-size:.95rem;font-weight:700;color:var(--text);margin:0}
|
||||
|
||||
.req-item{padding:16px 20px;border-bottom:1px solid rgba(255,255,255,.04);display:flex;align-items:flex-start;gap:16px;transition:background .15s}
|
||||
.req-item:last-child{border-bottom:none}
|
||||
.req-item:hover{background:rgba(255,255,255,.02)}
|
||||
|
||||
.req-vote{display:flex;flex-direction:column;align-items:center;gap:4px;min-width:52px}
|
||||
.req-vote-btn{width:44px;height:44px;border-radius:50%;border:1px solid var(--border);background:transparent;color:var(--text3);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s;font-size:.95rem}
|
||||
.req-vote-btn:hover,.req-vote-btn.voted{border-color:var(--accent);background:rgba(255,45,125,.12);color:var(--accent)}
|
||||
.req-vote-cnt{font-size:.82rem;font-weight:700;color:var(--text2)}
|
||||
|
||||
.req-body{flex:1;min-width:0}
|
||||
.req-title{font-size:.95rem;font-weight:600;color:var(--text);margin-bottom:3px}
|
||||
.req-ori{font-size:.78rem;color:var(--text3);margin-bottom:6px}
|
||||
.req-note{font-size:.78rem;color:var(--text2);margin-bottom:8px;line-height:1.5}
|
||||
.req-meta{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
|
||||
.req-status{font-size:.7rem;padding:2px 10px;border-radius:20px;font-weight:600}
|
||||
.req-by{font-size:.72rem;color:var(--text3)}
|
||||
.req-admin-note{font-size:.75rem;color:#f0883e;margin-top:6px;display:flex;align-items:center;gap:5px}
|
||||
|
||||
.toast-msg{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);background:#161b22;border:1px solid #30363d;border-radius:10px;padding:12px 20px;color:var(--text);font-size:.85rem;z-index:9999;animation:fadeInUp .3s ease;box-shadow:0 8px 24px rgba(0,0,0,.5)}
|
||||
@keyframes fadeInUp{from{transform:translateX(-50%) translateY(10px);opacity:0}to{transform:translateX(-50%) translateY(0);opacity:1}}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div style="padding-top:var(--nav-h)">
|
||||
|
||||
<div class="req-hero">
|
||||
<h1><i class="bi bi-plus-circle" style="color:var(--accent)"></i> Anime İsteği</h1>
|
||||
<p>İzlemek istediğin ama sitede olmayan bir anime var mı? Buradan bildir, en çok istenen animeleri ekliyoruz.</p>
|
||||
</div>
|
||||
|
||||
<div class="req-wrap">
|
||||
|
||||
{{-- İstek formu (sadece üyeler) --}}
|
||||
@auth
|
||||
<div class="req-form-card" id="req-form-card">
|
||||
<h2><i class="bi bi-send" style="color:var(--accent)"></i> Yeni İstek Gönder</h2>
|
||||
<div id="req-success" style="display:none;background:rgba(63,185,80,.1);border:1px solid #3fb95040;border-radius:8px;padding:12px 16px;color:#3fb950;font-size:.88rem;margin-bottom:16px"></div>
|
||||
<div class="rf-field">
|
||||
<label class="rf-label">Anime Adı (Türkçe veya bilinen ismi) *</label>
|
||||
<input id="rf-title" type="text" class="rf-input" placeholder="örn: Demon Slayer" maxlength="200">
|
||||
</div>
|
||||
<div class="rf-field">
|
||||
<label class="rf-label">Orijinal / İngilizce Adı</label>
|
||||
<input id="rf-ori" type="text" class="rf-input" placeholder="örn: Kimetsu no Yaiba" maxlength="200">
|
||||
</div>
|
||||
<div class="rf-field">
|
||||
<label class="rf-label">Not / Açıklama</label>
|
||||
<textarea id="rf-note" class="rf-input rf-textarea" placeholder="Hangi sezon, neden istiyorsun? vs."></textarea>
|
||||
</div>
|
||||
<button class="rf-submit" id="rf-btn" onclick="submitRequest()">
|
||||
<i class="bi bi-send-fill"></i> İstek Gönder
|
||||
</button>
|
||||
</div>
|
||||
@else
|
||||
<div style="background:var(--surface);border:1px solid var(--border);border-radius:16px;padding:28px;text-align:center;margin-bottom:32px">
|
||||
<i class="bi bi-lock" style="font-size:2rem;color:var(--text3);margin-bottom:12px;display:block"></i>
|
||||
<p style="color:var(--text2);margin-bottom:16px">Anime isteği göndermek için giriş yapman gerekiyor.</p>
|
||||
<a href="{{ route('frontend.login') }}" style="padding:10px 24px;background:var(--accent);border-radius:20px;color:#fff;font-weight:600;text-decoration:none;font-size:.88rem">Giriş Yap</a>
|
||||
<a href="{{ route('frontend.register') }}" style="padding:10px 24px;background:#21262d;border-radius:20px;color:var(--text2);font-weight:600;text-decoration:none;font-size:.88rem;margin-left:8px">Kayıt Ol</a>
|
||||
</div>
|
||||
@endauth
|
||||
|
||||
{{-- İstekler listesi --}}
|
||||
<div class="req-list-card">
|
||||
<div class="req-list-head">
|
||||
<h2><i class="bi bi-list-ul" style="color:var(--accent);margin-right:6px"></i>Tüm İstekler</h2>
|
||||
<span style="font-size:.78rem;color:var(--text3)">{{ $requests->total() }} istek</span>
|
||||
</div>
|
||||
|
||||
@forelse($requests as $req)
|
||||
@php
|
||||
$st = \App\Models\AnimeRequest::STATUSES[$req->status] ?? ['label'=>$req->status,'color'=>'#8b949e'];
|
||||
$hasVoted = in_array($req->id, $votedIds);
|
||||
@endphp
|
||||
<div class="req-item">
|
||||
<div class="req-vote">
|
||||
@auth
|
||||
<button class="req-vote-btn {{ $hasVoted?'voted':'' }}" id="vote-btn-{{ $req->id }}" onclick="voteRequest({{ $req->id }})">
|
||||
<i class="bi bi-heart{{ $hasVoted?'-fill':'' }}" id="vote-icon-{{ $req->id }}"></i>
|
||||
</button>
|
||||
@else
|
||||
<a href="{{ route('frontend.login') }}" class="req-vote-btn"><i class="bi bi-heart"></i></a>
|
||||
@endauth
|
||||
<span class="req-vote-cnt" id="vote-cnt-{{ $req->id }}">{{ $req->vote_count }}</span>
|
||||
</div>
|
||||
<div class="req-body">
|
||||
<div class="req-title">{{ $req->title }}</div>
|
||||
@if($req->original_title)<div class="req-ori">{{ $req->original_title }}</div>@endif
|
||||
@if($req->note)<div class="req-note">{{ Str::limit($req->note, 150) }}</div>@endif
|
||||
<div class="req-meta">
|
||||
<span class="req-status" style="background:{{ $st['color'] }}22;color:{{ $st['color'] }};border:1px solid {{ $st['color'] }}44">{{ $st['label'] }}</span>
|
||||
@if($req->user)<span class="req-by">{{ $req->user->name }} tarafından istendi</span>@endif
|
||||
<span class="req-by">· {{ $req->created_at->diffForHumans() }}</span>
|
||||
</div>
|
||||
@if($req->admin_note)
|
||||
<div class="req-admin-note"><i class="bi bi-shield-check"></i> {{ $req->admin_note }}</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div style="padding:40px;text-align:center;color:var(--text3)">Henüz istek yok. İlk isteği sen gönder!</div>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
<div class="mt-4">{{ $requests->links() }}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
const CSRF = document.querySelector('meta[name=csrf-token]')?.content||'';
|
||||
|
||||
async function submitRequest() {
|
||||
const title = document.getElementById('rf-title').value.trim();
|
||||
if (!title) { showToast('Anime adı zorunlu!'); return; }
|
||||
|
||||
const btn = document.getElementById('rf-btn');
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<i class="bi bi-hourglass-split"></i> Gönderiliyor...';
|
||||
|
||||
try {
|
||||
const res = await fetch('{{ route("anime.request.store") }}', {
|
||||
method:'POST',
|
||||
headers:{'Content-Type':'application/json','X-CSRF-TOKEN':CSRF},
|
||||
body: JSON.stringify({
|
||||
title,
|
||||
original_title: document.getElementById('rf-ori').value.trim(),
|
||||
note: document.getElementById('rf-note').value.trim(),
|
||||
})
|
||||
});
|
||||
const d = await res.json();
|
||||
const msg = d.merged
|
||||
? `Bu anime zaten istekler listesinde! Oyun eklendi (toplam: ${d.vote_count} oy).`
|
||||
: `İsteğin gönderildi! Teşekkürler 🎉`;
|
||||
document.getElementById('req-success').style.display = 'block';
|
||||
document.getElementById('req-success').textContent = msg;
|
||||
document.getElementById('rf-title').value = '';
|
||||
document.getElementById('rf-ori').value = '';
|
||||
document.getElementById('rf-note').value = '';
|
||||
setTimeout(()=>location.reload(), 2000);
|
||||
} catch(e) {
|
||||
showToast('Bir hata oluştu, tekrar dene.');
|
||||
}
|
||||
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = '<i class="bi bi-send-fill"></i> İstek Gönder';
|
||||
}
|
||||
|
||||
async function voteRequest(id) {
|
||||
const btn = document.getElementById(`vote-btn-${id}`);
|
||||
const ico = document.getElementById(`vote-icon-${id}`);
|
||||
if (btn) btn.disabled = true;
|
||||
try {
|
||||
const res = await fetch(`/anime-request/${id}/vote`, {
|
||||
method:'POST',
|
||||
headers:{'Content-Type':'application/json','X-CSRF-TOKEN':CSRF},
|
||||
body:'{}'
|
||||
});
|
||||
if (res.status === 401) { window.location = '{{ route("frontend.login") }}'; return; }
|
||||
if (!res.ok) { showToast('Bir hata oluştu.'); return; }
|
||||
const d = await res.json();
|
||||
document.getElementById(`vote-cnt-${id}`).textContent = d.vote_count;
|
||||
if (d.voted) {
|
||||
btn.classList.add('voted');
|
||||
ico.className = 'bi bi-heart-fill';
|
||||
} else {
|
||||
btn.classList.remove('voted');
|
||||
ico.className = 'bi bi-heart';
|
||||
}
|
||||
} catch(e) {
|
||||
showToast('Bağlantı hatası, tekrar dene.');
|
||||
}
|
||||
if (btn) btn.disabled = false;
|
||||
}
|
||||
|
||||
function showToast(msg) {
|
||||
const t = document.createElement('div');
|
||||
t.className='toast-msg';
|
||||
t.textContent=msg;
|
||||
document.body.appendChild(t);
|
||||
setTimeout(()=>t.remove(), 3000);
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,57 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title','Şifremi Unuttum — Animexe')
|
||||
@push('styles')
|
||||
<style>
|
||||
.auth-page{min-height:calc(100vh - var(--nav-h));display:flex;align-items:center;justify-content:center;padding:40px 16px;position:relative;overflow:hidden;background:radial-gradient(ellipse 80% 60% at 50% -20%,rgba(184,77,255,.2),transparent 55%),radial-gradient(ellipse 50% 40% at 100% 100%,rgba(0,245,255,.1),transparent)}
|
||||
.auth-page::before{content:'';position:absolute;inset:0;pointer-events:none;background:linear-gradient(rgba(0,245,255,.03) 1px,transparent 1px),linear-gradient(90deg,rgba(0,245,255,.03) 1px,transparent 1px);background-size:40px 40px;mask-image:radial-gradient(ellipse 80% 80% at 50% 50%,black,transparent)}
|
||||
@keyframes auth-box-in{from{opacity:0;transform:translateY(24px) scale(.97)}to{opacity:1;transform:none}}
|
||||
.auth-box{background:linear-gradient(160deg,rgba(14,14,28,.97),rgba(8,8,18,.99));border:1px solid rgba(0,245,255,.22);border-radius:20px;padding:clamp(28px,5vw,44px);width:100%;max-width:440px;box-shadow:0 32px 80px rgba(0,0,0,.65),0 0 60px rgba(0,245,255,.08);position:relative;overflow:hidden;animation:auth-box-in .55s cubic-bezier(.22,1,.36,1) .1s both}
|
||||
.auth-box::before{content:'';position:absolute;top:0;left:10%;right:10%;height:1px;background:linear-gradient(90deg,transparent,var(--accent2),var(--accent),transparent);opacity:.7}
|
||||
.auth-logo{text-align:center;margin-bottom:28px}
|
||||
.auth-logo .name{font-family:var(--font-display);font-size:1.4rem;font-weight:900;letter-spacing:.22em;background:linear-gradient(105deg,#fff,var(--accent2),var(--accent));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;filter:drop-shadow(0 0 20px rgba(0,245,255,.3))}
|
||||
.auth-logo p{color:rgba(255,255,255,.35);font-size:.85rem;margin-top:5px}
|
||||
.f-group{margin-bottom:16px}
|
||||
.f-group label{display:block;font-size:.79rem;font-weight:700;color:rgba(255,255,255,.45);margin-bottom:7px;letter-spacing:.05em;text-transform:uppercase}
|
||||
.f-group input{width:100%;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.1);border-radius:10px;padding:12px 16px;color:var(--text);font-size:.9rem;outline:none;transition:border .18s,box-shadow .18s}
|
||||
.f-group input:focus{border-color:var(--accent2);box-shadow:0 0 0 2px rgba(0,245,255,.12);background:rgba(0,245,255,.04)}
|
||||
.f-group input::placeholder{color:rgba(255,255,255,.2)}
|
||||
.auth-btn{width:100%;padding:13px;border-radius:12px;border:none;cursor:pointer;background:linear-gradient(135deg,var(--accent),var(--accent3));color:#fff;font-size:.93rem;font-weight:800;transition:transform .14s,box-shadow .18s;box-shadow:0 0 32px rgba(255,45,125,.35),0 4px 20px rgba(0,0,0,.35)}
|
||||
.auth-btn:hover{transform:translateY(-2px);box-shadow:0 0 44px rgba(255,45,125,.5)}
|
||||
.auth-switch{text-align:center;font-size:.85rem;color:rgba(255,255,255,.35);margin-top:20px}
|
||||
.auth-switch a{color:var(--accent2);font-weight:700}
|
||||
.status-box{background:rgba(0,245,255,.07);border:1px solid rgba(0,245,255,.2);border-radius:10px;padding:14px 16px;font-size:.87rem;color:var(--accent2);margin-bottom:20px}
|
||||
</style>
|
||||
@endpush
|
||||
@section('content')
|
||||
<div class="auth-page">
|
||||
<div class="auth-box">
|
||||
<div class="auth-logo">
|
||||
<div class="name">ANIMEXE</div>
|
||||
<p>Şifre sıfırlama</p>
|
||||
</div>
|
||||
|
||||
@if(session('status'))
|
||||
<div class="status-box"><i class="bi bi-check-circle-fill"></i> {{ session('status') }}</div>
|
||||
@endif
|
||||
|
||||
@if($errors->any())
|
||||
<div class="alert alert-err">{{ $errors->first() }}</div>
|
||||
@endif
|
||||
|
||||
<p style="font-size:.87rem;color:rgba(255,255,255,.4);margin-bottom:20px">Kayıtlı e-posta adresini gir, sana şifre sıfırlama bağlantısı gönderelim.</p>
|
||||
|
||||
<form action="{{ route('password.request') }}" method="POST">
|
||||
@csrf
|
||||
<div class="f-group">
|
||||
<label>E-posta Adresi</label>
|
||||
<input type="email" name="email" value="{{ old('email') }}" placeholder="ornek@email.com" required autofocus>
|
||||
</div>
|
||||
<button type="submit" class="auth-btn">Sıfırlama Bağlantısı Gönder</button>
|
||||
</form>
|
||||
|
||||
<div class="auth-switch">
|
||||
<a href="{{ route('frontend.login') }}"><i class="bi bi-arrow-left"></i> Girişe dön</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,159 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title','Giriş Yap — Animexe')
|
||||
@push('styles')
|
||||
<style>
|
||||
/* ═══════════════════════════════════════════════════
|
||||
AUTH PAGE PREMIUM
|
||||
═══════════════════════════════════════════════════ */
|
||||
.auth-page{
|
||||
min-height:calc(100vh - var(--nav-h));
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
padding:40px 16px;
|
||||
position:relative;overflow:hidden;
|
||||
background:
|
||||
radial-gradient(ellipse 80% 60% at 50% -20%,rgba(184,77,255,.2),transparent 55%),
|
||||
radial-gradient(ellipse 50% 40% at 100% 100%,rgba(0,245,255,.1),transparent),
|
||||
radial-gradient(ellipse 40% 35% at 0% 100%,rgba(255,45,125,.08),transparent);
|
||||
}
|
||||
/* Animated grid lines in background */
|
||||
.auth-page::before{
|
||||
content:'';position:absolute;inset:0;pointer-events:none;
|
||||
background:
|
||||
linear-gradient(rgba(0,245,255,.03) 1px,transparent 1px),
|
||||
linear-gradient(90deg,rgba(0,245,255,.03) 1px,transparent 1px);
|
||||
background-size:40px 40px;
|
||||
mask-image:radial-gradient(ellipse 80% 80% at 50% 50%,black,transparent);
|
||||
}
|
||||
|
||||
@keyframes auth-box-in{
|
||||
from{opacity:0;transform:translateY(24px) scale(.97)}
|
||||
to{opacity:1;transform:none}
|
||||
}
|
||||
.auth-box{
|
||||
background:linear-gradient(160deg,rgba(14,14,28,.97),rgba(8,8,18,.99));
|
||||
border:1px solid rgba(0,245,255,.22);
|
||||
border-radius:20px;padding:clamp(28px,5vw,44px);
|
||||
width:100%;max-width:440px;
|
||||
box-shadow:0 32px 80px rgba(0,0,0,.65),0 0 60px rgba(0,245,255,.08),0 0 80px rgba(255,45,125,.05);
|
||||
position:relative;overflow:hidden;
|
||||
animation:auth-box-in .55s cubic-bezier(.22,1,.36,1) .1s both;
|
||||
}
|
||||
/* Top accent line */
|
||||
.auth-box::before{
|
||||
content:'';position:absolute;top:0;left:10%;right:10%;height:1px;
|
||||
background:linear-gradient(90deg,transparent,var(--accent2),var(--accent),transparent);
|
||||
opacity:.7;
|
||||
}
|
||||
|
||||
.auth-logo{text-align:center;margin-bottom:28px}
|
||||
.auth-logo .name{
|
||||
font-family:var(--font-display);font-size:1.4rem;font-weight:900;letter-spacing:.22em;
|
||||
background:linear-gradient(105deg,#fff 0%,var(--accent2) 40%,var(--accent) 100%);
|
||||
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;
|
||||
text-shadow:none;
|
||||
filter:drop-shadow(0 0 20px rgba(0,245,255,.3));
|
||||
}
|
||||
.auth-logo p{color:rgba(255,255,255,.35);font-size:.85rem;margin-top:5px}
|
||||
.auth-title{font-size:1.18rem;font-weight:800;margin-bottom:22px;color:#fff}
|
||||
.f-group{margin-bottom:16px;position:relative}
|
||||
.f-group label{display:block;font-size:.79rem;font-weight:700;color:rgba(255,255,255,.45);margin-bottom:7px;letter-spacing:.05em;text-transform:uppercase}
|
||||
.f-group input{
|
||||
width:100%;
|
||||
background:rgba(255,255,255,.04);
|
||||
border:1px solid rgba(255,255,255,.1);
|
||||
border-radius:10px;
|
||||
padding:12px 16px;
|
||||
color:var(--text);font-size:.9rem;outline:none;
|
||||
transition:border .18s,box-shadow .18s,background .18s;
|
||||
}
|
||||
.f-group input:focus{
|
||||
border-color:var(--accent2);
|
||||
box-shadow:0 0 0 2px rgba(0,245,255,.12),0 0 24px rgba(0,245,255,.06);
|
||||
background:rgba(0,245,255,.04);
|
||||
}
|
||||
.f-group input::placeholder{color:rgba(255,255,255,.2)}
|
||||
.f-err{font-size:.78rem;color:#fca5a5;margin-top:5px;display:flex;align-items:center;gap:4px}
|
||||
.f-check{display:flex;align-items:center;gap:9px;margin-bottom:18px}
|
||||
.f-check input{width:16px;height:16px;accent-color:var(--accent);border-radius:4px}
|
||||
.f-check label{font-size:.84rem;color:rgba(255,255,255,.45);cursor:pointer}
|
||||
.auth-btn{
|
||||
width:100%;padding:13px;border-radius:12px;border:none;cursor:pointer;
|
||||
background:linear-gradient(135deg,var(--accent) 0%,var(--accent3) 100%);
|
||||
color:#fff;font-size:.93rem;font-weight:800;letter-spacing:.03em;
|
||||
transition:transform .14s,box-shadow .18s;
|
||||
box-shadow:0 0 32px rgba(255,45,125,.35),0 4px 20px rgba(0,0,0,.35);
|
||||
position:relative;overflow:hidden;
|
||||
}
|
||||
.auth-btn:hover{transform:translateY(-2px);box-shadow:0 0 44px rgba(255,45,125,.5),0 6px 24px rgba(0,0,0,.35)}
|
||||
.auth-btn:active{transform:translateY(0)}
|
||||
.auth-sep{text-align:center;margin:18px 0;color:rgba(255,255,255,.2);font-size:.8rem;position:relative}
|
||||
.auth-sep::before,.auth-sep::after{content:'';position:absolute;top:50%;width:38%;height:1px;background:rgba(255,255,255,.08)}
|
||||
.auth-sep::before{left:0}
|
||||
.auth-sep::after{right:0}
|
||||
.auth-switch{text-align:center;font-size:.85rem;color:rgba(255,255,255,.35);margin-top:20px}
|
||||
.auth-switch a{color:var(--accent2);font-weight:700}
|
||||
.auth-switch a:hover{text-decoration:underline;text-shadow:0 0 12px rgba(0,245,255,.5)}
|
||||
.social-btns{display:flex;flex-direction:column;gap:10px;margin-top:4px}
|
||||
.social-btn{
|
||||
display:flex;align-items:center;justify-content:center;gap:10px;
|
||||
width:100%;padding:11px 16px;border-radius:10px;border:1px solid rgba(255,255,255,.1);
|
||||
background:rgba(255,255,255,.04);color:rgba(255,255,255,.82);
|
||||
font-size:.88rem;font-weight:600;cursor:pointer;
|
||||
transition:background .15s,border-color .15s,transform .12s;
|
||||
text-decoration:none;
|
||||
}
|
||||
.social-btn:hover{background:rgba(255,255,255,.09);border-color:rgba(255,255,255,.22);transform:translateY(-1px)}
|
||||
.social-btn svg{width:18px;height:18px;flex-shrink:0}
|
||||
</style>
|
||||
@endpush
|
||||
@section('content')
|
||||
<div class="auth-page">
|
||||
<div class="auth-box">
|
||||
<div class="auth-logo">
|
||||
<div class="name">ANIMEXE</div>
|
||||
<p>Hesabına giriş yap</p>
|
||||
</div>
|
||||
|
||||
@if($errors->any())
|
||||
<div class="alert alert-err">{{ $errors->first() }}</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('frontend.login') }}" method="POST">
|
||||
@csrf
|
||||
<div class="f-group">
|
||||
<label>E-posta</label>
|
||||
<input type="email" name="email" value="{{ old('email') }}" placeholder="ornek@email.com" required autofocus>
|
||||
</div>
|
||||
<div class="f-group">
|
||||
<label>Şifre</label>
|
||||
<input type="password" name="password" placeholder="••••••••" required>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:18px">
|
||||
<div class="f-check" style="margin-bottom:0">
|
||||
<input type="checkbox" id="rem" name="remember">
|
||||
<label for="rem">Beni hatırla</label>
|
||||
</div>
|
||||
<a href="{{ route('password.request') }}" style="font-size:.82rem;color:rgba(255,255,255,.4);transition:color .15s" onmouseover="this.style.color='var(--accent2)'" onmouseout="this.style.color='rgba(255,255,255,.4)'">Şifremi unuttum</a>
|
||||
</div>
|
||||
<button type="submit" class="auth-btn">Giriş Yap</button>
|
||||
</form>
|
||||
|
||||
<div class="auth-sep" style="margin-top:22px">veya şununla devam et</div>
|
||||
|
||||
<div class="social-btns">
|
||||
<a href="{{ route('social.redirect', 'google') }}" class="social-btn">
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" fill="#4285F4"/><path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/><path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l3.66-2.84z" fill="#FBBC05"/><path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/></svg>
|
||||
Google ile devam et
|
||||
</a>
|
||||
<a href="{{ route('social.redirect', 'discord') }}" class="social-btn">
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="#5865F2"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/></svg>
|
||||
Discord ile devam et
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="auth-switch">
|
||||
Hesabın yok mu? <a href="{{ route('frontend.register') }}">Üye ol</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,110 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title','Üye Ol — Animexe')
|
||||
@push('styles')
|
||||
<style>
|
||||
/* ═══════════════════════════════════════════════���═══
|
||||
REGISTER PAGE PREMIUM (shared with login styles)
|
||||
═══════════════════════════════════════════════════ */
|
||||
.auth-page{
|
||||
min-height:calc(100vh - var(--nav-h));
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
padding:40px 16px;position:relative;overflow:hidden;
|
||||
background:
|
||||
radial-gradient(ellipse 80% 60% at 50% -20%,rgba(184,77,255,.2),transparent 55%),
|
||||
radial-gradient(ellipse 50% 40% at 100% 100%,rgba(0,245,255,.1),transparent),
|
||||
radial-gradient(ellipse 40% 35% at 0% 100%,rgba(255,45,125,.08),transparent);
|
||||
}
|
||||
.auth-page::before{
|
||||
content:'';position:absolute;inset:0;pointer-events:none;
|
||||
background:linear-gradient(rgba(0,245,255,.03) 1px,transparent 1px),linear-gradient(90deg,rgba(0,245,255,.03) 1px,transparent 1px);
|
||||
background-size:40px 40px;
|
||||
mask-image:radial-gradient(ellipse 80% 80% at 50% 50%,black,transparent);
|
||||
}
|
||||
@keyframes auth-box-in{from{opacity:0;transform:translateY(24px) scale(.97)}to{opacity:1;transform:none}}
|
||||
.auth-box{
|
||||
background:linear-gradient(160deg,rgba(14,14,28,.97),rgba(8,8,18,.99));
|
||||
border:1px solid rgba(0,245,255,.22);border-radius:20px;
|
||||
padding:clamp(24px,5vw,40px);width:100%;max-width:440px;
|
||||
box-shadow:0 32px 80px rgba(0,0,0,.65),0 0 60px rgba(0,245,255,.08),0 0 80px rgba(255,45,125,.05);
|
||||
position:relative;overflow:hidden;
|
||||
animation:auth-box-in .55s cubic-bezier(.22,1,.36,1) .1s both;
|
||||
}
|
||||
.auth-box::before{content:'';position:absolute;top:0;left:10%;right:10%;height:1px;background:linear-gradient(90deg,transparent,var(--accent2),var(--accent),transparent);opacity:.7}
|
||||
.auth-logo{text-align:center;margin-bottom:24px}
|
||||
.auth-logo .name{font-family:var(--font-display);font-size:1.4rem;font-weight:900;letter-spacing:.22em;background:linear-gradient(105deg,#fff 0%,var(--accent2) 40%,var(--accent) 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;filter:drop-shadow(0 0 20px rgba(0,245,255,.3))}
|
||||
.auth-logo p{color:rgba(255,255,255,.35);font-size:.85rem;margin-top:5px}
|
||||
.f-group{margin-bottom:14px;position:relative}
|
||||
.f-group label{display:block;font-size:.79rem;font-weight:700;color:rgba(255,255,255,.4);margin-bottom:6px;letter-spacing:.05em;text-transform:uppercase}
|
||||
.f-group input{width:100%;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.1);border-radius:10px;padding:12px 16px;color:var(--text);font-size:.9rem;outline:none;transition:border .18s,box-shadow .18s,background .18s}
|
||||
.f-group input:focus{border-color:var(--accent2);box-shadow:0 0 0 2px rgba(0,245,255,.12),0 0 24px rgba(0,245,255,.06);background:rgba(0,245,255,.04)}
|
||||
.f-group input::placeholder{color:rgba(255,255,255,.2)}
|
||||
.f-err{font-size:.78rem;color:#fca5a5;margin-top:5px}
|
||||
.auth-btn{width:100%;padding:13px;border-radius:12px;border:none;cursor:pointer;background:linear-gradient(135deg,var(--accent),var(--accent3));color:#fff;font-size:.93rem;font-weight:800;letter-spacing:.03em;transition:transform .14s,box-shadow .18s;margin-top:4px;box-shadow:0 0 32px rgba(255,45,125,.35),0 4px 20px rgba(0,0,0,.35);position:relative;overflow:hidden}
|
||||
.auth-btn:hover{transform:translateY(-2px);box-shadow:0 0 44px rgba(255,45,125,.5),0 6px 24px rgba(0,0,0,.35)}
|
||||
.auth-terms{font-size:.78rem;color:rgba(255,255,255,.25);text-align:center;margin-top:12px}
|
||||
.auth-terms a{color:rgba(255,255,255,.45)}
|
||||
.auth-switch{text-align:center;font-size:.85rem;color:rgba(255,255,255,.35);margin-top:16px}
|
||||
.auth-switch a{color:var(--accent2);font-weight:700}
|
||||
.auth-switch a:hover{text-decoration:underline;text-shadow:0 0 12px rgba(0,245,255,.5)}
|
||||
.auth-sep{text-align:center;margin:18px 0;color:rgba(255,255,255,.2);font-size:.8rem;position:relative}
|
||||
.auth-sep::before,.auth-sep::after{content:'';position:absolute;top:50%;width:38%;height:1px;background:rgba(255,255,255,.08)}
|
||||
.auth-sep::before{left:0}.auth-sep::after{right:0}
|
||||
.social-btns{display:flex;flex-direction:column;gap:10px}
|
||||
.social-btn{display:flex;align-items:center;justify-content:center;gap:10px;width:100%;padding:11px 16px;border-radius:10px;border:1px solid rgba(255,255,255,.1);background:rgba(255,255,255,.04);color:rgba(255,255,255,.82);font-size:.88rem;font-weight:600;cursor:pointer;transition:background .15s,border-color .15s,transform .12s;text-decoration:none}
|
||||
.social-btn:hover{background:rgba(255,255,255,.09);border-color:rgba(255,255,255,.22);transform:translateY(-1px)}
|
||||
.social-btn svg{width:18px;height:18px;flex-shrink:0}
|
||||
</style>
|
||||
@endpush
|
||||
@section('content')
|
||||
<div class="auth-page">
|
||||
<div class="auth-box">
|
||||
<div class="auth-logo">
|
||||
<div class="name">ANIMEXE</div>
|
||||
<p>Ücretsiz hesap oluştur</p>
|
||||
</div>
|
||||
|
||||
@if($errors->any())
|
||||
<div class="alert alert-err">{{ $errors->first() }}</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('frontend.register') }}" method="POST">
|
||||
@csrf
|
||||
<div class="f-group">
|
||||
<label>Adın</label>
|
||||
<input type="text" name="name" value="{{ old('name') }}" placeholder="Adın Soyadın" required autofocus>
|
||||
</div>
|
||||
<div class="f-group">
|
||||
<label>E-posta</label>
|
||||
<input type="email" name="email" value="{{ old('email') }}" placeholder="ornek@email.com" required>
|
||||
</div>
|
||||
<div class="f-group">
|
||||
<label>Şifre</label>
|
||||
<input type="password" name="password" placeholder="En az 6 karakter" required>
|
||||
</div>
|
||||
<div class="f-group">
|
||||
<label>Şifre Tekrar</label>
|
||||
<input type="password" name="password_confirmation" placeholder="Şifreni tekrarla" required>
|
||||
</div>
|
||||
<button type="submit" class="auth-btn">Üye Ol — Ücretsiz</button>
|
||||
<p class="auth-terms">Üye olarak <a href="#" style="color:var(--accent)">Kullanım Koşulları</a>'nı kabul etmiş olursunuz.</p>
|
||||
</form>
|
||||
|
||||
<div class="auth-sep">veya şununla kayıt ol</div>
|
||||
|
||||
<div class="social-btns">
|
||||
<a href="{{ route('social.redirect', 'google') }}" class="social-btn">
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" fill="#4285F4"/><path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/><path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l3.66-2.84z" fill="#FBBC05"/><path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/></svg>
|
||||
Google ile kayıt ol
|
||||
</a>
|
||||
<a href="{{ route('social.redirect', 'discord') }}" class="social-btn">
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="#5865F2"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/></svg>
|
||||
Discord ile kayıt ol
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="auth-switch">
|
||||
Zaten üye misin? <a href="{{ route('frontend.login') }}">Giriş yap</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,53 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title','Yeni Şifre Belirle — Animexe')
|
||||
@push('styles')
|
||||
<style>
|
||||
.auth-page{min-height:calc(100vh - var(--nav-h));display:flex;align-items:center;justify-content:center;padding:40px 16px;position:relative;overflow:hidden;background:radial-gradient(ellipse 80% 60% at 50% -20%,rgba(184,77,255,.2),transparent 55%),radial-gradient(ellipse 50% 40% at 100% 100%,rgba(0,245,255,.1),transparent)}
|
||||
.auth-page::before{content:'';position:absolute;inset:0;pointer-events:none;background:linear-gradient(rgba(0,245,255,.03) 1px,transparent 1px),linear-gradient(90deg,rgba(0,245,255,.03) 1px,transparent 1px);background-size:40px 40px;mask-image:radial-gradient(ellipse 80% 80% at 50% 50%,black,transparent)}
|
||||
@keyframes auth-box-in{from{opacity:0;transform:translateY(24px) scale(.97)}to{opacity:1;transform:none}}
|
||||
.auth-box{background:linear-gradient(160deg,rgba(14,14,28,.97),rgba(8,8,18,.99));border:1px solid rgba(0,245,255,.22);border-radius:20px;padding:clamp(28px,5vw,44px);width:100%;max-width:440px;box-shadow:0 32px 80px rgba(0,0,0,.65),0 0 60px rgba(0,245,255,.08);position:relative;overflow:hidden;animation:auth-box-in .55s cubic-bezier(.22,1,.36,1) .1s both}
|
||||
.auth-box::before{content:'';position:absolute;top:0;left:10%;right:10%;height:1px;background:linear-gradient(90deg,transparent,var(--accent2),var(--accent),transparent);opacity:.7}
|
||||
.auth-logo{text-align:center;margin-bottom:28px}
|
||||
.auth-logo .name{font-family:var(--font-display);font-size:1.4rem;font-weight:900;letter-spacing:.22em;background:linear-gradient(105deg,#fff,var(--accent2),var(--accent));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;filter:drop-shadow(0 0 20px rgba(0,245,255,.3))}
|
||||
.auth-logo p{color:rgba(255,255,255,.35);font-size:.85rem;margin-top:5px}
|
||||
.f-group{margin-bottom:16px}
|
||||
.f-group label{display:block;font-size:.79rem;font-weight:700;color:rgba(255,255,255,.45);margin-bottom:7px;letter-spacing:.05em;text-transform:uppercase}
|
||||
.f-group input{width:100%;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.1);border-radius:10px;padding:12px 16px;color:var(--text);font-size:.9rem;outline:none;transition:border .18s,box-shadow .18s}
|
||||
.f-group input:focus{border-color:var(--accent2);box-shadow:0 0 0 2px rgba(0,245,255,.12);background:rgba(0,245,255,.04)}
|
||||
.f-group input::placeholder{color:rgba(255,255,255,.2)}
|
||||
.auth-btn{width:100%;padding:13px;border-radius:12px;border:none;cursor:pointer;background:linear-gradient(135deg,var(--accent),var(--accent3));color:#fff;font-size:.93rem;font-weight:800;transition:transform .14s,box-shadow .18s;box-shadow:0 0 32px rgba(255,45,125,.35),0 4px 20px rgba(0,0,0,.35)}
|
||||
.auth-btn:hover{transform:translateY(-2px)}
|
||||
</style>
|
||||
@endpush
|
||||
@section('content')
|
||||
<div class="auth-page">
|
||||
<div class="auth-box">
|
||||
<div class="auth-logo">
|
||||
<div class="name">ANIMEXE</div>
|
||||
<p>Yeni şifre belirle</p>
|
||||
</div>
|
||||
|
||||
@if($errors->any())
|
||||
<div class="alert alert-err">{{ $errors->first() }}</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('password.update') }}" method="POST">
|
||||
@csrf
|
||||
<input type="hidden" name="token" value="{{ $token }}">
|
||||
<div class="f-group">
|
||||
<label>E-posta Adresi</label>
|
||||
<input type="email" name="email" value="{{ old('email', $email) }}" required>
|
||||
</div>
|
||||
<div class="f-group">
|
||||
<label>Yeni Şifre</label>
|
||||
<input type="password" name="password" placeholder="En az 6 karakter" required>
|
||||
</div>
|
||||
<div class="f-group">
|
||||
<label>Şifre Tekrar</label>
|
||||
<input type="password" name="password_confirmation" placeholder="Şifreni tekrarla" required>
|
||||
</div>
|
||||
<button type="submit" class="auth-btn">Şifremi Güncelle</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,48 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title','E-posta Doğrulama — Animexe')
|
||||
@push('styles')
|
||||
<style>
|
||||
.auth-page{min-height:calc(100vh - var(--nav-h));display:flex;align-items:center;justify-content:center;padding:40px 16px;background:radial-gradient(ellipse 80% 60% at 50% -20%,rgba(184,77,255,.2),transparent 55%)}
|
||||
@keyframes auth-box-in{from{opacity:0;transform:translateY(24px) scale(.97)}to{opacity:1;transform:none}}
|
||||
.auth-box{background:linear-gradient(160deg,rgba(14,14,28,.97),rgba(8,8,18,.99));border:1px solid rgba(0,245,255,.22);border-radius:20px;padding:clamp(28px,5vw,44px);width:100%;max-width:440px;box-shadow:0 32px 80px rgba(0,0,0,.65);position:relative;overflow:hidden;text-align:center;animation:auth-box-in .55s cubic-bezier(.22,1,.36,1) .1s both}
|
||||
.auth-box::before{content:'';position:absolute;top:0;left:10%;right:10%;height:1px;background:linear-gradient(90deg,transparent,var(--accent2),var(--accent),transparent);opacity:.7}
|
||||
.ve-icon{font-size:3rem;margin-bottom:16px;filter:drop-shadow(0 0 16px rgba(0,245,255,.4))}
|
||||
.ve-title{font-size:1.1rem;font-weight:800;color:#fff;margin-bottom:10px}
|
||||
.ve-text{font-size:.88rem;color:rgba(255,255,255,.4);line-height:1.7;margin-bottom:24px}
|
||||
.auth-btn{display:inline-block;padding:12px 28px;border-radius:12px;border:none;cursor:pointer;background:linear-gradient(135deg,var(--accent),var(--accent3));color:#fff;font-size:.9rem;font-weight:800;transition:transform .14s;box-shadow:0 0 28px rgba(255,45,125,.3);width:100%}
|
||||
.auth-btn:hover{transform:translateY(-2px)}
|
||||
.status-box{background:rgba(0,245,255,.07);border:1px solid rgba(0,245,255,.2);border-radius:10px;padding:12px 16px;font-size:.85rem;color:var(--accent2);margin-bottom:20px}
|
||||
.logout-link{display:block;margin-top:16px;font-size:.82rem;color:rgba(255,255,255,.3)}
|
||||
.logout-link a{color:rgba(255,255,255,.4)}
|
||||
</style>
|
||||
@endpush
|
||||
@section('content')
|
||||
<div class="auth-page">
|
||||
<div class="auth-box">
|
||||
<div class="ve-icon">📧</div>
|
||||
<div class="ve-title">E-postanı Doğrula</div>
|
||||
<p class="ve-text">
|
||||
<strong style="color:#fff">{{ auth()->user()->email }}</strong> adresine doğrulama bağlantısı gönderdik.<br>
|
||||
Gelen kutunu kontrol et. Spam klasörüne de bakmanı öneririz.
|
||||
</p>
|
||||
|
||||
@if(session('status'))
|
||||
<div class="status-box"><i class="bi bi-check-circle-fill"></i> {{ session('status') }}</div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('verification.send') }}">
|
||||
@csrf
|
||||
<button type="submit" class="auth-btn">
|
||||
<i class="bi bi-envelope-fill"></i> Tekrar Gönder
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="logout-link">
|
||||
<form method="POST" action="{{ route('frontend.logout') }}" style="display:inline">
|
||||
@csrf
|
||||
<a href="#" onclick="this.closest('form').submit()">Çıkış yap</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,144 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Anime Blog — Rehberler, İncelemeler ve Öneriler | Animexe')
|
||||
@section('meta_description', 'Animexe anime blogunda izleme rehberleri, anime incelemeleri, tür önerileri ve AI destekli içerikler keşfedin.')
|
||||
@section('meta_keywords', 'anime blog, anime rehberi, anime inceleme, anime önerisi, animexe blog')
|
||||
@section('og_type', 'website')
|
||||
@push('styles')
|
||||
<style>
|
||||
.blog-hero{background:linear-gradient(180deg,rgba(12,12,26,.95) 0%,var(--bg) 100%);padding:calc(var(--nav-h) + 32px) 24px 36px;border-bottom:1px solid rgba(0,245,255,.12)}
|
||||
.blog-hero h1{font-family:var(--font-display);font-size:1.6rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase;margin-bottom:8px}
|
||||
.blog-hero p{color:var(--text2);font-size:.95rem;max-width:520px}
|
||||
.blog-grid{display:grid;grid-template-columns:1fr 300px;gap:32px;max-width:1200px;margin:0 auto}
|
||||
.blog-card{
|
||||
background:linear-gradient(145deg,rgba(17,17,31,.95),rgba(10,10,20,.98));
|
||||
border:1px solid rgba(0,245,255,.1);border-radius:var(--r2);overflow:hidden;
|
||||
transition:transform .2s,box-shadow .22s,border-color .2s;
|
||||
display:flex;flex-direction:column;
|
||||
}
|
||||
.blog-card:hover{transform:translateY(-4px);border-color:rgba(255,45,125,.4);box-shadow:0 16px 48px rgba(0,0,0,.5),0 0 32px rgba(255,45,125,.1)}
|
||||
.blog-thumb{aspect-ratio:16/9;overflow:hidden;background:var(--surface2)}
|
||||
.blog-thumb img{width:100%;height:100%;object-fit:cover;transition:transform .3s}
|
||||
.blog-card:hover .blog-thumb img{transform:scale(1.05)}
|
||||
.blog-thumb-ph{width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:var(--text3);font-size:2.5rem}
|
||||
.blog-body{padding:18px;flex:1;display:flex;flex-direction:column}
|
||||
.blog-category{font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.1em;color:var(--accent2);margin-bottom:8px}
|
||||
.blog-title{font-size:.95rem;font-weight:700;color:var(--text);line-height:1.45;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;margin-bottom:8px}
|
||||
.blog-excerpt{font-size:.8rem;color:var(--text2);line-height:1.55;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;flex:1}
|
||||
.blog-footer{display:flex;align-items:center;justify-content:space-between;margin-top:14px;padding-top:12px;border-top:1px solid rgba(0,245,255,.08)}
|
||||
.blog-date{font-size:.72rem;color:var(--text3)}
|
||||
.blog-read{font-size:.72rem;color:var(--text3);display:flex;align-items:center;gap:4px}
|
||||
.blog-ai-badge{display:inline-flex;align-items:center;gap:4px;font-size:.65rem;font-weight:700;
|
||||
padding:2px 8px;border-radius:999px;background:rgba(124,58,237,.2);border:1px solid rgba(124,58,237,.3);
|
||||
color:#a78bfa;margin-bottom:8px}
|
||||
.sidebar-card{background:rgba(17,17,31,.8);border:1px solid rgba(0,245,255,.1);border-radius:var(--r2);padding:18px;margin-bottom:20px}
|
||||
.sidebar-title{font-family:var(--font-display);font-size:.72rem;text-transform:uppercase;letter-spacing:.1em;color:var(--accent2);margin-bottom:14px;font-weight:700}
|
||||
.sidebar-item{display:flex;gap:10px;padding:8px 0;border-bottom:1px solid rgba(0,245,255,.05);align-items:flex-start}
|
||||
.sidebar-item:last-child{border-bottom:none}
|
||||
.sidebar-item-title{font-size:.8rem;font-weight:600;color:var(--text);line-height:1.4;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
|
||||
.sidebar-item-date{font-size:.68rem;color:var(--text3);margin-top:3px}
|
||||
.sidebar-thumb{width:52px;height:52px;border-radius:6px;overflow:hidden;flex-shrink:0;background:var(--surface2)}
|
||||
.sidebar-thumb img{width:100%;height:100%;object-fit:cover}
|
||||
.posts-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:20px}
|
||||
@media(max-width:900px){
|
||||
.blog-grid{grid-template-columns:1fr}
|
||||
.blog-sidebar{display:none}
|
||||
}
|
||||
@media(max-width:480px){
|
||||
.posts-grid{grid-template-columns:1fr}
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="blog-hero">
|
||||
<div style="max-width:1200px;margin:0 auto">
|
||||
<h1><i class="bi bi-journal-richtext" style="color:var(--accent2);font-size:1.2rem;margin-right:10px"></i>Anime Blog</h1>
|
||||
<p>AI destekli anime rehberleri, izleme önerileri ve derinlemesine incelemeler.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="blog-grid">
|
||||
<div>
|
||||
@if($posts->count())
|
||||
<div class="posts-grid">
|
||||
@foreach($posts as $post)
|
||||
<a href="{{ route('blog.show', $post->slug) }}" class="blog-card" style="text-decoration:none">
|
||||
<div class="blog-thumb">
|
||||
@if($post->coverUrl)
|
||||
<img src="{{ $post->coverUrl }}" alt="{{ $post->title }}" loading="lazy">
|
||||
@else
|
||||
<div class="blog-thumb-ph"><i class="bi bi-journal-richtext"></i></div>
|
||||
@endif
|
||||
</div>
|
||||
<div class="blog-body">
|
||||
@if($post->ai_generated)
|
||||
<div class="blog-ai-badge"><i class="bi bi-stars" style="font-size:.6rem"></i> AI İçerik</div>
|
||||
@endif
|
||||
@if($post->anime)
|
||||
<div class="blog-category">{{ $post->anime->title }}</div>
|
||||
@endif
|
||||
<div class="blog-title">{{ $post->title }}</div>
|
||||
<div class="blog-excerpt">{{ $post->excerpt }}</div>
|
||||
<div class="blog-footer">
|
||||
<span class="blog-date">{{ $post->published_at?->format('d.m.Y') }}</span>
|
||||
<span class="blog-read"><i class="bi bi-clock" style="font-size:.65rem"></i> {{ $post->reading_time }} dk</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
@if($posts->hasPages())
|
||||
<div style="margin-top:32px">{{ $posts->links('frontend.pagination') }}</div>
|
||||
@endif
|
||||
@else
|
||||
<div style="text-align:center;padding:80px 20px;color:var(--text3)">
|
||||
<i class="bi bi-journal-text" style="font-size:3rem;opacity:.25;display:block;margin-bottom:14px"></i>
|
||||
<p>Henüz blog yazısı yok. Yakında yapay zeka destekli içerikler gelecek!</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<aside class="blog-sidebar">
|
||||
{{-- Son Yazılar --}}
|
||||
@if($recent->count())
|
||||
<div class="sidebar-card">
|
||||
<div class="sidebar-title">Son Yazılar</div>
|
||||
@foreach($recent as $p)
|
||||
<a href="{{ route('blog.show', $p->slug) }}" class="sidebar-item" style="text-decoration:none">
|
||||
<div class="sidebar-thumb">
|
||||
@if($p->coverUrl)<img src="{{ $p->coverUrl }}" alt="" loading="lazy">
|
||||
@else<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:var(--text3)"><i class="bi bi-journal-text"></i></div>@endif
|
||||
</div>
|
||||
<div>
|
||||
<div class="sidebar-item-title">{{ $p->title }}</div>
|
||||
<div class="sidebar-item-date">{{ $p->published_at?->format('d.m.Y') }}</div>
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- En Çok Okunanlar --}}
|
||||
@if($popular->count())
|
||||
<div class="sidebar-card">
|
||||
<div class="sidebar-title"><i class="bi bi-fire" style="color:var(--accent)"></i> En Çok Okunanlar</div>
|
||||
@foreach($popular as $p)
|
||||
<a href="{{ route('blog.show', $p->slug) }}" class="sidebar-item" style="text-decoration:none">
|
||||
<div class="sidebar-thumb">
|
||||
@if($p->coverUrl)<img src="{{ $p->coverUrl }}" alt="" loading="lazy">
|
||||
@else<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:var(--text3)"><i class="bi bi-journal-text"></i></div>@endif
|
||||
</div>
|
||||
<div>
|
||||
<div class="sidebar-item-title">{{ $p->title }}</div>
|
||||
<div class="sidebar-item-date">{{ number_format($p->views) }} görüntülenme</div>
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,234 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@php
|
||||
$__canon = rtrim(\App\Models\Setting::get('seo_canonical_domain', config('app.url')), '/') . route('blog.show', $post->slug, false);
|
||||
$__ogImg = $post->coverUrl;
|
||||
$__pubDate = $post->published_at?->toIso8601String();
|
||||
$__modDate = $post->updated_at?->toIso8601String();
|
||||
$__faqItems = $post->faq ?? [];
|
||||
@endphp
|
||||
@section('title', ($post->meta_title ?: $post->title) . ' — Animexe Blog')
|
||||
@section('meta_description', $post->meta_description ?: $post->excerpt)
|
||||
@section('meta_keywords', $post->meta_keywords)
|
||||
@section('og_type', 'article')
|
||||
@section('og_title', $post->title)
|
||||
@section('og_description', $post->excerpt)
|
||||
@if($__ogImg)@section('og_image', $__ogImg)@endif
|
||||
@section('canonical', $__canon)
|
||||
@section('robots', 'index, follow')
|
||||
|
||||
@section('schema')
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@@context":"https://schema.org",
|
||||
"@@type":"BlogPosting",
|
||||
"headline":"{{ addslashes($post->title) }}",
|
||||
"description":"{{ addslashes($post->excerpt ?? '') }}",
|
||||
"url":"{{ $__canon }}",
|
||||
"datePublished":"{{ $__pubDate }}",
|
||||
"dateModified":"{{ $__modDate }}",
|
||||
"author":{"@@type":"Organization","name":"Animexe","url":"{{ rtrim(\App\Models\Setting::get('seo_canonical_domain',config('app.url')),'/') }}"},
|
||||
"publisher":{"@@type":"Organization","name":"Animexe","logo":{"@@type":"ImageObject","url":"{{ url('/logo.jpg') }}"}},
|
||||
"image":"{{ $__ogImg ?: url('/logo.jpg') }}",
|
||||
"inLanguage":"tr-TR",
|
||||
"keywords":"{{ addslashes($post->meta_keywords ?? '') }}"
|
||||
}
|
||||
</script>
|
||||
@if(count($__faqItems) > 0)
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@@context":"https://schema.org",
|
||||
"@@type":"FAQPage",
|
||||
"mainEntity":[
|
||||
@foreach($__faqItems as $i => $faq)
|
||||
{"@@type":"Question","name":"{{ addslashes($faq['q'] ?? '') }}","acceptedAnswer":{"@@type":"Answer","text":"{{ addslashes($faq['a'] ?? '') }}"}}{{ $i < count($__faqItems)-1 ? ',' : '' }}
|
||||
@endforeach
|
||||
]
|
||||
}
|
||||
</script>
|
||||
@endif
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@@context":"https://schema.org",
|
||||
"@@type":"BreadcrumbList",
|
||||
"itemListElement":[
|
||||
{"@@type":"ListItem","position":1,"name":"Ana Sayfa","item":"{{ rtrim(\App\Models\Setting::get('seo_canonical_domain',config('app.url')),'/') }}/"},
|
||||
{"@@type":"ListItem","position":2,"name":"Blog","item":"{{ rtrim(\App\Models\Setting::get('seo_canonical_domain',config('app.url')),'/') }}/blog"},
|
||||
{"@@type":"ListItem","position":3,"name":"{{ addslashes($post->title) }}","item":"{{ $__canon }}"}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
@push('styles')
|
||||
<style>
|
||||
.blog-layout{display:grid;grid-template-columns:1fr 300px;gap:40px;max-width:1160px;margin:0 auto}
|
||||
.blog-article{}
|
||||
.blog-hero-img{width:100%;aspect-ratio:16/9;object-fit:cover;border-radius:var(--r2);margin-bottom:28px;
|
||||
box-shadow:0 8px 32px rgba(0,0,0,.5)}
|
||||
.blog-meta-bar{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-bottom:20px;padding-bottom:16px;border-bottom:1px solid rgba(0,245,255,.1)}
|
||||
.blog-meta-item{display:flex;align-items:center;gap:6px;font-size:.78rem;color:var(--text3)}
|
||||
.blog-meta-item i{font-size:.75rem;color:var(--accent2)}
|
||||
.blog-ai-badge-lg{display:inline-flex;align-items:center;gap:6px;padding:4px 12px;border-radius:999px;
|
||||
background:linear-gradient(135deg,rgba(124,58,237,.2),rgba(232,67,147,.1));
|
||||
border:1px solid rgba(124,58,237,.3);color:#a78bfa;font-size:.78rem;font-weight:700;margin-bottom:16px}
|
||||
.blog-h1{font-family:var(--font-display);font-size:1.55rem;font-weight:800;letter-spacing:.04em;
|
||||
line-height:1.35;color:var(--text);margin-bottom:20px}
|
||||
.blog-content{color:var(--text2);line-height:1.85;font-size:.95rem}
|
||||
.blog-content h2{font-family:var(--font-display);font-size:1.1rem;font-weight:700;color:var(--text);
|
||||
margin:32px 0 14px;letter-spacing:.04em;text-transform:uppercase;
|
||||
border-left:3px solid var(--accent2);padding-left:12px}
|
||||
.blog-content h3{font-size:.95rem;font-weight:700;color:var(--text);margin:22px 0 10px}
|
||||
.blog-content p{margin-bottom:16px}
|
||||
.blog-content ul,.blog-content ol{padding-left:24px;margin-bottom:16px}
|
||||
.blog-content li{margin-bottom:8px}
|
||||
.blog-content strong{color:var(--text);font-weight:700}
|
||||
.blog-content a{color:var(--accent2);text-decoration:underline;text-decoration-color:rgba(0,245,255,.4)}
|
||||
.blog-content a:hover{color:var(--accent);text-decoration-color:rgba(255,45,125,.6)}
|
||||
.faq-section{margin-top:40px;padding-top:28px;border-top:1px solid rgba(0,245,255,.1)}
|
||||
.faq-section h2{font-family:var(--font-display);font-size:1rem;font-weight:800;text-transform:uppercase;
|
||||
letter-spacing:.06em;color:var(--accent2);margin-bottom:20px}
|
||||
.faq-item{background:rgba(17,17,31,.8);border:1px solid rgba(0,245,255,.1);border-radius:var(--r2);
|
||||
padding:18px;margin-bottom:12px}
|
||||
.faq-item h3{font-size:.9rem;font-weight:700;color:var(--text);margin-bottom:10px;line-height:1.4}
|
||||
.faq-item p{font-size:.85rem;color:var(--text2);line-height:1.65;margin:0}
|
||||
.cta-box{margin-top:36px;padding:28px;background:linear-gradient(135deg,rgba(255,45,125,.12),rgba(0,245,255,.08));
|
||||
border:1px solid rgba(255,45,125,.3);border-radius:var(--r2);text-align:center}
|
||||
.cta-box h3{font-family:var(--font-display);font-size:1rem;font-weight:800;text-transform:uppercase;
|
||||
letter-spacing:.06em;color:var(--text);margin-bottom:12px}
|
||||
.cta-btn{display:inline-flex;align-items:center;gap:8px;padding:12px 28px;border-radius:999px;
|
||||
background:linear-gradient(135deg,var(--accent),var(--accent3));color:#fff;
|
||||
font-weight:700;font-size:.9rem;text-decoration:none;transition:transform .16s,box-shadow .18s;
|
||||
box-shadow:0 0 24px rgba(255,45,125,.4)}
|
||||
.cta-btn:hover{transform:translateY(-2px);box-shadow:0 0 36px rgba(255,45,125,.55);color:#fff}
|
||||
.related-card{
|
||||
background:rgba(17,17,31,.8);border:1px solid rgba(0,245,255,.1);border-radius:var(--r);
|
||||
overflow:hidden;transition:border-color .2s;display:flex;gap:12px;align-items:flex-start;padding:12px;
|
||||
}
|
||||
.related-card:hover{border-color:rgba(255,45,125,.3)}
|
||||
.related-thumb{width:64px;height:64px;border-radius:6px;overflow:hidden;flex-shrink:0;background:var(--surface2)}
|
||||
.related-thumb img{width:100%;height:100%;object-fit:cover}
|
||||
.linked-animes{margin-top:28px;padding:20px;background:rgba(0,245,255,.04);border:1px solid rgba(0,245,255,.12);border-radius:var(--r2)}
|
||||
.linked-animes h3{font-size:.82rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--accent2);margin-bottom:14px}
|
||||
.la-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:10px}
|
||||
@media(max-width:900px){
|
||||
.blog-layout{grid-template-columns:1fr}
|
||||
.blog-sidebar-wrap{display:none}
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="section" style="padding-top:calc(var(--nav-h) + 28px)">
|
||||
<div class="blog-layout">
|
||||
<article class="blog-article" itemscope itemtype="https://schema.org/BlogPosting">
|
||||
|
||||
@if($post->coverUrl)
|
||||
<img src="{{ $post->coverUrl }}" alt="{{ $post->title }}"
|
||||
class="blog-hero-img" itemprop="image" fetchpriority="high">
|
||||
@endif
|
||||
|
||||
@if($post->ai_generated)
|
||||
<div class="blog-ai-badge-lg"><i class="bi bi-stars"></i> AI Destekli İçerik</div>
|
||||
@endif
|
||||
|
||||
<h1 class="blog-h1" itemprop="headline">{{ $post->title }}</h1>
|
||||
|
||||
<div class="blog-meta-bar">
|
||||
@if($post->published_at)
|
||||
<span class="blog-meta-item">
|
||||
<i class="bi bi-calendar3"></i>
|
||||
<time itemprop="datePublished" datetime="{{ $post->published_at->toIso8601String() }}">
|
||||
{{ $post->published_at->format('d F Y') }}
|
||||
</time>
|
||||
</span>
|
||||
@endif
|
||||
<span class="blog-meta-item"><i class="bi bi-clock"></i> {{ $post->reading_time }} dk okuma</span>
|
||||
@if($post->anime)
|
||||
<span class="blog-meta-item">
|
||||
<i class="bi bi-play-circle"></i>
|
||||
<a href="{{ $post->anime?->detailUrl ?? '#' }}" style="color:var(--accent2)">{{ $post->anime->title }}</a>
|
||||
</span>
|
||||
@endif
|
||||
@if($post->focus_keyword)
|
||||
<span class="blog-meta-item"><i class="bi bi-tag"></i> {{ $post->focus_keyword }}</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="blog-content" itemprop="articleBody">
|
||||
{!! $post->content !!}
|
||||
</div>
|
||||
|
||||
{{-- FAQ Bölümü --}}
|
||||
@if(count($__faqItems) > 0)
|
||||
<div class="faq-section">
|
||||
<h2>Sıkça Sorulan Sorular</h2>
|
||||
@foreach($__faqItems as $faq)
|
||||
<div class="faq-item">
|
||||
<h3>{{ $faq['q'] ?? '' }}</h3>
|
||||
<p>{{ $faq['a'] ?? '' }}</p>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- İlgili Anime Linkleri --}}
|
||||
@if($linkedAnimes->count())
|
||||
<div class="linked-animes">
|
||||
<h3><i class="bi bi-collection-play me-1"></i>Bu Yazıda Bahsedilen Animeler</h3>
|
||||
<div class="la-grid">
|
||||
@foreach($linkedAnimes as $la)
|
||||
<a href="{{ $la->detailUrl }}" class="a-card">
|
||||
<div class="a-poster">
|
||||
@if($la->coverUrl)<img src="{{ $la->coverUrl }}" alt="{{ $la->title }}" loading="lazy">
|
||||
@else<div class="a-no-img"><i class="bi bi-image"></i></div>@endif
|
||||
@if($la->rating)<span class="a-rating"><i class="bi bi-star-fill" style="font-size:.6rem"></i>{{ number_format($la->rating,1) }}</span>@endif
|
||||
</div>
|
||||
<div class="a-info">
|
||||
<div class="a-title">{{ $la->title }}</div>
|
||||
<div class="a-meta">{{ $la->release_year }}</div>
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- CTA --}}
|
||||
@if($post->anime)
|
||||
<div class="cta-box">
|
||||
<h3>{{ $post->anime->title }} İzle</h3>
|
||||
<p style="color:var(--text2);font-size:.88rem;margin-bottom:18px">
|
||||
Animexe'de Türkçe altyazılı veya dublajlı ücretsiz izle.
|
||||
</p>
|
||||
<a href="{{ $post->anime?->detailUrl ?? '#' }}" class="cta-btn">
|
||||
<i class="bi bi-play-fill"></i> Hemen İzle
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
</article>
|
||||
|
||||
{{-- Sidebar --}}
|
||||
<aside class="blog-sidebar-wrap">
|
||||
@if($related->count())
|
||||
<div style="background:rgba(17,17,31,.8);border:1px solid rgba(0,245,255,.1);border-radius:var(--r2);padding:18px">
|
||||
<div style="font-family:var(--font-display);font-size:.72rem;text-transform:uppercase;letter-spacing:.1em;color:var(--accent2);margin-bottom:14px;font-weight:700">İlgili Yazılar</div>
|
||||
<div style="display:flex;flex-direction:column;gap:10px">
|
||||
@foreach($related as $rp)
|
||||
<a href="{{ route('blog.show', $rp->slug) }}" class="related-card" style="text-decoration:none">
|
||||
<div class="related-thumb">
|
||||
@if($rp->coverUrl)<img src="{{ $rp->coverUrl }}" alt="" loading="lazy">
|
||||
@else<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:var(--text3)"><i class="bi bi-journal-text"></i></div>@endif
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-size:.8rem;font-weight:600;color:var(--text);line-height:1.4;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden">{{ $rp->title }}</div>
|
||||
<div style="font-size:.68rem;color:var(--text3);margin-top:4px">{{ $rp->published_at?->format('d.m.Y') }}</div>
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,114 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Zaman Kapsüllerim | Animexe')
|
||||
@push('styles')
|
||||
<style>
|
||||
.cap-hero{padding-top:calc(var(--nav-h) + 40px);padding-bottom:32px;text-align:center;background:radial-gradient(ellipse at 50% 0%,rgba(100,80,255,.12) 0%,transparent 70%)}
|
||||
.cap-hero h1{font-size:2rem;font-weight:900;margin-bottom:8px}
|
||||
.cap-hero h1 span{color:#a78bfa}
|
||||
.cap-hero p{color:rgba(255,255,255,.4);font-size:.9rem}
|
||||
.cap-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px;padding:0 0 60px}
|
||||
.cap-card{border-radius:16px;padding:20px;position:relative;overflow:hidden;border:1px solid rgba(255,255,255,.08)}
|
||||
.cap-card.locked{background:linear-gradient(135deg,rgba(20,18,40,.9),rgba(10,8,22,.9))}
|
||||
.cap-card.unlocked{background:linear-gradient(135deg,rgba(100,80,255,.12),rgba(60,40,180,.08));border-color:rgba(167,139,250,.25)}
|
||||
.cap-card.opened{background:linear-gradient(135deg,rgba(0,200,100,.06),rgba(0,160,80,.04));border-color:rgba(0,200,100,.2)}
|
||||
.cap-lock-icon{font-size:2rem;margin-bottom:10px;display:block}
|
||||
.cap-anime{font-size:.72rem;font-weight:700;color:rgba(167,139,250,.8);text-transform:uppercase;letter-spacing:.07em;margin-bottom:6px}
|
||||
.cap-date{font-size:.78rem;color:rgba(255,255,255,.35);margin-bottom:14px}
|
||||
.cap-locked-msg{font-size:.82rem;color:rgba(255,255,255,.25);text-align:center;padding:16px 0}
|
||||
.cap-message{font-size:.88rem;line-height:1.6;color:rgba(255,255,255,.8);background:rgba(255,255,255,.04);border-radius:10px;padding:14px;border-left:3px solid #a78bfa;font-style:italic}
|
||||
.cap-open-btn{width:100%;margin-top:14px;padding:10px;border-radius:10px;border:none;background:rgba(167,139,250,.2);color:#a78bfa;font-weight:700;font-size:.88rem;cursor:pointer;font-family:inherit;transition:background .15s}
|
||||
.cap-open-btn:hover{background:rgba(167,139,250,.35)}
|
||||
.cap-tag{display:inline-block;padding:2px 10px;border-radius:20px;font-size:.65rem;font-weight:700;margin-bottom:10px}
|
||||
.cap-tag.locked{background:rgba(255,255,255,.06);color:rgba(255,255,255,.3)}
|
||||
.cap-tag.unlocked{background:rgba(167,139,250,.12);color:#a78bfa}
|
||||
.cap-tag.opened{background:rgba(0,200,100,.1);color:#00c864}
|
||||
|
||||
.cap-countdown{font-size:.78rem;color:rgba(255,255,255,.3);margin-top:8px;text-align:center}
|
||||
</style>
|
||||
@endpush
|
||||
@section('content')
|
||||
<div style="max-width:1100px;margin:0 auto;padding:0 20px">
|
||||
|
||||
<div class="cap-hero">
|
||||
<h1>⏳ Zaman <span>Kapsüllerim</span></h1>
|
||||
<p>Geçmiş benliğinden gelen mesajlar.</p>
|
||||
</div>
|
||||
|
||||
@if($capsules->isEmpty())
|
||||
<div style="text-align:center;padding:80px 20px;color:rgba(255,255,255,.25)">
|
||||
<i class="bi bi-hourglass" style="font-size:3rem;display:block;margin-bottom:16px"></i>
|
||||
Henüz kapsül oluşturmadın.<br>
|
||||
<small style="font-size:.8rem">Bir anime sayfasından ilk kez izlerken kapsül bırakabilirsin.</small>
|
||||
</div>
|
||||
@else
|
||||
<div class="cap-grid">
|
||||
@foreach($capsules as $cap)
|
||||
<div class="cap-card {{ $cap['opened'] ? 'opened' : ($cap['unlocked'] ? 'unlocked' : 'locked') }}" id="cap-{{ $cap['id'] }}">
|
||||
<span class="cap-lock-icon">{{ $cap['opened'] ? '📭' : ($cap['unlocked'] ? '🔓' : '🔒') }}</span>
|
||||
<span class="cap-tag {{ $cap['opened'] ? 'opened' : ($cap['unlocked'] ? 'unlocked' : 'locked') }}">
|
||||
{{ $cap['opened'] ? 'Açıldı' : ($cap['unlocked'] ? 'Açılabilir' : 'Kilitli') }}
|
||||
</span>
|
||||
<div class="cap-anime">
|
||||
<a href="{{ $cap['anime_url'] }}" style="color:inherit;text-decoration:none">{{ $cap['anime'] }}</a>
|
||||
</div>
|
||||
<div class="cap-date">
|
||||
<i class="bi bi-calendar3"></i>
|
||||
Oluşturuldu: {{ $cap['created_at'] }} · Açılış: {{ $cap['unlock_at'] }}
|
||||
</div>
|
||||
|
||||
@if($cap['opened'] || $cap['unlocked'])
|
||||
@if($cap['message'])
|
||||
<div class="cap-message">{{ $cap['message'] }}</div>
|
||||
@else
|
||||
<button class="cap-open-btn" onclick="openCapsule({{ $cap['id'] }}, this)">
|
||||
<i class="bi bi-envelope-open"></i> Kapsülü Aç
|
||||
</button>
|
||||
@endif
|
||||
@else
|
||||
<div class="cap-locked-msg">
|
||||
<i class="bi bi-lock"></i><br>
|
||||
Bu kapsül {{ $cap['unlock_at'] }} tarihinde açılacak
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
@push('scripts')
|
||||
<script>
|
||||
const CSRF = document.querySelector('meta[name="csrf-token"]')?.content ?? '';
|
||||
|
||||
async function openCapsule(id, btn) {
|
||||
btn.disabled = true;
|
||||
btn.textContent = 'Açılıyor...';
|
||||
const r = await fetch(`/kapsul/${id}/ac`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': CSRF, 'Accept': 'application/json' },
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
const d = await r.json();
|
||||
if (d.ok) {
|
||||
const card = document.getElementById('cap-' + id);
|
||||
btn.remove();
|
||||
const msg = document.createElement('div');
|
||||
msg.className = 'cap-message';
|
||||
msg.textContent = d.message;
|
||||
card.appendChild(msg);
|
||||
card.classList.remove('unlocked');
|
||||
card.classList.add('opened');
|
||||
card.querySelector('.cap-lock-icon').textContent = '📭';
|
||||
const tag = card.querySelector('.cap-tag');
|
||||
tag.textContent = 'Açıldı';
|
||||
tag.className = 'cap-tag opened';
|
||||
} else {
|
||||
btn.disabled = false;
|
||||
btn.textContent = 'Kapsülü Aç';
|
||||
if (window.showToast) showToast(d.error || 'Hata oluştu.', 'error');
|
||||
else alert(d.error || 'Hata oluştu.');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,35 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Ödeme Başarısız | Animexe')
|
||||
|
||||
@push('styles')
|
||||
<style>
|
||||
.ck-result{max-width:480px;margin:80px auto;text-align:center;padding:0 16px}
|
||||
.ck-result-icon{font-size:4rem;margin-bottom:20px;color:#ff4d6d}
|
||||
.ck-result h1{font-size:1.5rem;font-weight:800;margin-bottom:10px}
|
||||
.ck-result p{color:rgba(255,255,255,.55);margin-bottom:28px;line-height:1.6}
|
||||
.ck-result-btns{display:flex;gap:12px;justify-content:center;flex-wrap:wrap}
|
||||
.ck-result-btn{display:inline-flex;align-items:center;gap:8px;padding:12px 24px;border-radius:10px;font-weight:700;text-decoration:none;transition:opacity .15s}
|
||||
.ck-result-btn.primary{background:linear-gradient(135deg,#00f5ff,#b84dff);color:#fff}
|
||||
.ck-result-btn.secondary{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1);color:rgba(255,255,255,.7)}
|
||||
.ck-result-btn:hover{opacity:.85;color:inherit}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="ck-result">
|
||||
<div class="ck-result-icon"><i class="bi bi-x-circle-fill"></i></div>
|
||||
<h1>Ödeme Başarısız</h1>
|
||||
<p>
|
||||
Ödeme işlemi tamamlanamadı. Kart bilgilerini kontrol edip tekrar deneyebilirsin
|
||||
veya farklı bir kart kullanabilirsin.
|
||||
</p>
|
||||
<div class="ck-result-btns">
|
||||
<a href="{{ route('premium.plans') }}" class="ck-result-btn primary">
|
||||
<i class="bi bi-arrow-repeat"></i> Tekrar Dene
|
||||
</a>
|
||||
<a href="{{ route('anime.index') }}" class="ck-result-btn secondary">
|
||||
<i class="bi bi-house"></i> Ana Sayfa
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,31 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Ödeme | Animexe')
|
||||
|
||||
@push('styles')
|
||||
<style>
|
||||
.ck-pay-wrap{max-width:540px;margin:40px auto;padding:0 16px}
|
||||
.ck-pay-head{text-align:center;margin-bottom:24px}
|
||||
.ck-pay-head h1{font-size:1.2rem;font-weight:700;margin-bottom:6px}
|
||||
.ck-pay-head p{color:rgba(255,255,255,.45);font-size:.85rem}
|
||||
.ck-iyzico-box{background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.08);border-radius:16px;padding:24px;min-height:400px}
|
||||
.ck-secure{display:flex;align-items:center;gap:8px;justify-content:center;margin-top:16px;font-size:.75rem;color:rgba(255,255,255,.3)}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="ck-pay-wrap">
|
||||
<div class="ck-pay-head">
|
||||
<h1><i class="bi bi-credit-card-fill me-2" style="color:#00f5ff"></i>Kart Bilgileri</h1>
|
||||
<p>{{ $plan->name }} — ₺{{ number_format($plan->price, 0) }} / {{ $plan->duration_days }} gün</p>
|
||||
</div>
|
||||
|
||||
<div class="ck-iyzico-box">
|
||||
{!! $formContent !!}
|
||||
</div>
|
||||
|
||||
<div class="ck-secure">
|
||||
<i class="bi bi-shield-check" style="color:#00f5ff"></i>
|
||||
Kart bilgileriniz iyzico'nun güvenli sunucularında işlenir
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,104 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', $plan->name . ' — Ödeme | Animexe')
|
||||
|
||||
@push('styles')
|
||||
<style>
|
||||
.ck-wrap{max-width:860px;margin:40px auto;padding:0 16px;display:grid;grid-template-columns:1fr 1fr;gap:28px}
|
||||
@media(max-width:640px){.ck-wrap{grid-template-columns:1fr}}
|
||||
.ck-plan{background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);border-radius:16px;padding:28px}
|
||||
.ck-plan-name{font-size:1.4rem;font-weight:800;color:#00f5ff;margin-bottom:6px}
|
||||
.ck-plan-price{font-size:2.4rem;font-weight:900;margin:12px 0 4px}
|
||||
.ck-plan-dur{color:rgba(255,255,255,.45);font-size:.85rem;margin-bottom:20px}
|
||||
.ck-features{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:8px}
|
||||
.ck-features li{color:rgba(255,255,255,.7);font-size:.88rem;display:flex;align-items:center;gap:8px}
|
||||
.ck-features li i{color:#00f5ff;font-size:.9rem}
|
||||
.ck-form{background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);border-radius:16px;padding:28px}
|
||||
.ck-form h2{font-size:1rem;font-weight:700;margin-bottom:20px;color:rgba(255,255,255,.85)}
|
||||
.ck-field{margin-bottom:16px}
|
||||
.ck-field label{display:block;font-size:.78rem;color:rgba(255,255,255,.5);margin-bottom:5px;font-weight:600;text-transform:uppercase;letter-spacing:.04em}
|
||||
.ck-field input{width:100%;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1);border-radius:8px;padding:10px 14px;color:#fff;font-size:.9rem;outline:none;transition:border-color .15s;box-sizing:border-box}
|
||||
.ck-field input:focus{border-color:rgba(0,245,255,.4)}
|
||||
.ck-field input::placeholder{color:rgba(255,255,255,.25)}
|
||||
.ck-field small{display:block;font-size:.73rem;color:rgba(255,255,255,.3);margin-top:4px}
|
||||
.ck-submit{width:100%;padding:13px;background:linear-gradient(135deg,#00f5ff,#b84dff);border:none;border-radius:10px;color:#fff;font-weight:800;font-size:1rem;cursor:pointer;margin-top:6px;transition:opacity .15s}
|
||||
.ck-submit:hover{opacity:.9}
|
||||
.ck-secure{display:flex;align-items:center;gap:8px;justify-content:center;margin-top:14px;font-size:.75rem;color:rgba(255,255,255,.3)}
|
||||
.ck-back{display:inline-flex;align-items:center;gap:6px;color:rgba(255,255,255,.4);font-size:.82rem;margin-bottom:24px;text-decoration:none}
|
||||
.ck-back:hover{color:rgba(255,255,255,.7)}
|
||||
.ck-err{background:rgba(255,60,60,.12);border:1px solid rgba(255,60,60,.3);border-radius:8px;padding:10px 14px;color:#ff6b6b;font-size:.85rem;margin-bottom:16px}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="ck-wrap">
|
||||
<div>
|
||||
<a href="{{ route('premium.plans') }}" class="ck-back"><i class="bi bi-arrow-left"></i> Planlara dön</a>
|
||||
<div class="ck-plan">
|
||||
<div class="ck-plan-name">{{ $plan->name }}</div>
|
||||
<div class="ck-plan-price"><span style="font-size:1.2rem;font-weight:400">₺</span>{{ number_format($plan->price, 0) }}</div>
|
||||
<div class="ck-plan-dur">{{ $plan->duration_days }} günlük premium üyelik</div>
|
||||
@if(($plan->trial_days ?? 0) > 0)
|
||||
<div style="display:inline-flex;align-items:center;gap:6px;padding:5px 12px;border-radius:20px;background:rgba(0,245,255,.1);border:1px solid rgba(0,245,255,.25);color:#00f5ff;font-size:.75rem;font-weight:700;margin-bottom:16px">
|
||||
<i class="bi bi-gift-fill"></i> İlk {{ $plan->trial_days }} gün ücretsiz
|
||||
</div>
|
||||
@endif
|
||||
@if(!empty($plan->features))
|
||||
<ul class="ck-features">
|
||||
@foreach($plan->features as $feat)
|
||||
<li><i class="bi bi-check2-circle"></i> {{ $feat }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ck-form">
|
||||
<h2><i class="bi bi-person-fill me-2"></i>Fatura Bilgileri</h2>
|
||||
|
||||
@if($errors->has('general'))
|
||||
<div class="ck-err"><i class="bi bi-exclamation-circle me-1"></i>{{ $errors->first('general') }}</div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('checkout.initialize', $plan) }}">
|
||||
@csrf
|
||||
<div class="ck-field">
|
||||
<label>Ad Soyad *</label>
|
||||
<input type="text" name="full_name" value="{{ old('full_name', auth()->user()->name) }}" placeholder="Adınız Soyadınız" required>
|
||||
@error('full_name')<span style="color:#ff6b6b;font-size:.75rem">{{ $message }}</span>@enderror
|
||||
</div>
|
||||
<div class="ck-field">
|
||||
<label>E-posta</label>
|
||||
<input type="text" value="{{ auth()->user()->email }}" disabled style="opacity:.5;cursor:not-allowed">
|
||||
</div>
|
||||
<div class="ck-field">
|
||||
<label>Telefon *</label>
|
||||
<input type="tel" name="phone" value="{{ old('phone') }}" placeholder="05XX XXX XX XX" required>
|
||||
@error('phone')<span style="color:#ff6b6b;font-size:.75rem">{{ $message }}</span>@enderror
|
||||
</div>
|
||||
<div class="ck-field">
|
||||
<label>İl *</label>
|
||||
<input type="text" name="city" value="{{ old('city') }}" placeholder="İstanbul" required>
|
||||
@error('city')<span style="color:#ff6b6b;font-size:.75rem">{{ $message }}</span>@enderror
|
||||
</div>
|
||||
<div class="ck-field">
|
||||
<label>Adres *</label>
|
||||
<input type="text" name="address" value="{{ old('address') }}" placeholder="Mahalle, sokak, bina no..." required>
|
||||
@error('address')<span style="color:#ff6b6b;font-size:.75rem">{{ $message }}</span>@enderror
|
||||
</div>
|
||||
<div class="ck-field">
|
||||
<label>TC Kimlik No <span style="color:rgba(255,255,255,.3)">(isteğe bağlı)</span></label>
|
||||
<input type="text" name="identity_no" value="{{ old('identity_no') }}" placeholder="11 haneli TC no" maxlength="11" inputmode="numeric">
|
||||
<small>iyzico güvenlik doğrulaması için istenir</small>
|
||||
@error('identity_no')<span style="color:#ff6b6b;font-size:.75rem">{{ $message }}</span>@enderror
|
||||
</div>
|
||||
<button type="submit" class="ck-submit">
|
||||
<i class="bi bi-credit-card-fill me-2"></i>Ödemeye Geç — ₺{{ number_format($plan->price, 0) }}
|
||||
</button>
|
||||
</form>
|
||||
<div class="ck-secure">
|
||||
<i class="bi bi-shield-check" style="color:#00f5ff"></i>
|
||||
iyzico altyapısıyla güvenli ödeme
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,29 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Ödeme Başarılı | Animexe')
|
||||
|
||||
@push('styles')
|
||||
<style>
|
||||
.ck-result{max-width:480px;margin:80px auto;text-align:center;padding:0 16px}
|
||||
.ck-result-icon{font-size:4rem;margin-bottom:20px;color:#00d4a4}
|
||||
.ck-result h1{font-size:1.5rem;font-weight:800;margin-bottom:10px}
|
||||
.ck-result p{color:rgba(255,255,255,.55);margin-bottom:28px;line-height:1.6}
|
||||
.ck-result-btn{display:inline-flex;align-items:center;gap:8px;padding:12px 28px;border-radius:10px;background:linear-gradient(135deg,#00f5ff,#b84dff);color:#fff;font-weight:700;text-decoration:none;transition:opacity .15s}
|
||||
.ck-result-btn:hover{opacity:.9;color:#fff}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="ck-result">
|
||||
<div class="ck-result-icon"><i class="bi bi-check-circle-fill"></i></div>
|
||||
<h1>Premium Aktif! 🎉</h1>
|
||||
<p>
|
||||
@if(session('checkout_plan_name'))
|
||||
<strong>{{ session('checkout_plan_name') }}</strong> planın aktif edildi.<br>
|
||||
@endif
|
||||
Artık tüm premium özelliklerden yararlanabilirsin.
|
||||
</p>
|
||||
<a href="{{ route('profile.settings') }}" class="ck-result-btn">
|
||||
<i class="bi bi-stars"></i> Kozmetiklerini Ayarla
|
||||
</a>
|
||||
</div>
|
||||
@endsection
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,96 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@php
|
||||
$__genreCanon = rtrim(\App\Models\Setting::get('seo_canonical_domain', config('app.url')), '/') . route('genre', $genre->slug, false);
|
||||
$__genreDesc = $genre->name . ' türündeki en iyi anime dizileri ve filmlerini Animexe\'de Türkçe altyazılı veya dublajlı ücretsiz izleyin. ' . $genre->name . ' anime listesi.';
|
||||
@endphp
|
||||
@section('title', $genre->name . ' Anime İzle - Türkçe Altyazılı | Animexe')
|
||||
@section('meta_description', $__genreDesc)
|
||||
@section('meta_keywords', $genre->name . ' anime izle, ' . $genre->name . ' türkçe anime izle, ' . $genre->name . ' anime, türkçe ' . $genre->name . ' anime, animexe ' . strtolower($genre->name))
|
||||
@section('og_title', $genre->name . ' Türündeki Animeler — Animexe')
|
||||
@section('og_description', $__genreDesc)
|
||||
@section('canonical', $__genreCanon)
|
||||
@section('schema')
|
||||
@if((\App\Models\Setting::get('seo_enable_schema','1')) === '1')
|
||||
@php $__gDomain = rtrim(\App\Models\Setting::get('seo_canonical_domain',config('app.url')),'/'); @endphp
|
||||
|
||||
{{-- CollectionPage + ItemList --}}
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@@context":"https://schema.org",
|
||||
"@@type":"CollectionPage",
|
||||
"name":"{{ addslashes($genre->name) }} Anime İzle - Türkçe Altyazılı",
|
||||
"description":"{{ addslashes($__genreDesc) }}",
|
||||
"url":"{{ $__genreCanon }}",
|
||||
"inLanguage":"tr-TR",
|
||||
"mainEntity":{
|
||||
"@@type":"ItemList",
|
||||
"name":"{{ addslashes($genre->name) }} Anime Listesi",
|
||||
"numberOfItems":{{ $animes->total() }},
|
||||
"itemListElement":[
|
||||
@foreach($animes->take(10) as $i => $ga)
|
||||
{"@@type":"ListItem","position":{{ $i+1 }},"name":"{{ addslashes($ga->title) }} İzle","url":"{{ $__gDomain }}/anime/{{ $ga->slug }}"}{{ $i < min(9,$animes->count()-1) ? ',' : '' }}
|
||||
@endforeach
|
||||
]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{{-- BreadcrumbList --}}
|
||||
@if((\App\Models\Setting::get('seo_enable_breadcrumb','1')) === '1')
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@@context":"https://schema.org",
|
||||
"@@type":"BreadcrumbList",
|
||||
"itemListElement":[
|
||||
{"@@type":"ListItem","position":1,"name":"Ana Sayfa","item":"{{ $__gDomain }}/"},
|
||||
{"@@type":"ListItem","position":2,"name":"Türler","item":"{{ $__gDomain }}/search"},
|
||||
{"@@type":"ListItem","position":3,"name":"{{ addslashes($genre->name) }} Anime İzle","item":"{{ $__genreCanon }}"}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
@endif
|
||||
@endif
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="section" style="padding-top:36px">
|
||||
<div class="section-hdr" style="margin-bottom:18px">
|
||||
<span class="section-title">
|
||||
<i class="bi bi-tag" style="font-size:.85rem;color:var(--accent2)"></i>
|
||||
{{ $genre->name }}
|
||||
</span>
|
||||
<span style="color:var(--text3);font-size:.82rem">{{ $animes->total() }} anime</span>
|
||||
</div>
|
||||
|
||||
@if($animes->count())
|
||||
<div class="a-grid">
|
||||
@foreach($animes as $anime)
|
||||
<a href="{{ $anime->detailUrl }}" class="a-card">
|
||||
<div class="a-poster">
|
||||
@if($anime->coverUrl)
|
||||
<img src="{{ $anime->coverUrl }}" alt="{{ $anime->title }}" loading="lazy">
|
||||
@else
|
||||
<div class="a-no-img"><i class="bi bi-image"></i></div>
|
||||
@endif
|
||||
@if($anime->type==='movie')<span class="a-badge">Film</span>@endif
|
||||
@if($anime->rating)<span class="a-rating"><i class="bi bi-star-fill" style="font-size:.65rem"></i>{{ number_format($anime->rating,1) }}</span>@endif
|
||||
<div class="a-hover-play"><div class="play-circle"><i class="bi bi-play-fill"></i></div></div>
|
||||
</div>
|
||||
<div class="a-info">
|
||||
<div class="a-title">{{ $anime->title }}</div>
|
||||
<div class="a-meta">{{ $anime->release_year }}</div>
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@if($animes->hasPages())
|
||||
<div style="margin-top:32px">{{ $animes->links('frontend.pagination') }}</div>
|
||||
@endif
|
||||
@else
|
||||
<div style="text-align:center;padding:64px 20px;color:var(--text3)">
|
||||
<i class="bi bi-collection" style="font-size:3rem;opacity:.25;display:block;margin-bottom:14px"></i>
|
||||
<p>Bu türde henüz anime bulunmuyor.</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endsection
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,118 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Telif Hakkı & DMCA | Animexe')
|
||||
@push('styles')
|
||||
<style>
|
||||
.legal-hero{padding-top:calc(var(--nav-h) + 48px);padding-bottom:28px;text-align:center}
|
||||
.legal-hero h1{font-size:1.8rem;font-weight:900;margin-bottom:8px}
|
||||
.legal-hero p{color:rgba(255,255,255,.4);font-size:.9rem}
|
||||
.legal-body{max-width:820px;margin:0 auto;padding:0 20px 80px}
|
||||
.legal-section{margin-bottom:36px}
|
||||
.legal-section h2{font-size:1.05rem;font-weight:800;color:#ff2d7d;margin-bottom:12px;padding-bottom:8px;border-bottom:1px solid rgba(255,255,255,.07)}
|
||||
.legal-section p,.legal-section li{font-size:.88rem;color:rgba(255,255,255,.65);line-height:1.8;margin-bottom:8px}
|
||||
.legal-section ul{padding-left:20px}
|
||||
.legal-section li{margin-bottom:4px}
|
||||
.legal-warn{background:rgba(245,158,11,.07);border:1px solid rgba(245,158,11,.25);border-radius:12px;padding:16px 20px;margin-bottom:32px}
|
||||
.legal-warn p{color:rgba(255,230,150,.7);font-size:.83rem;margin:0;line-height:1.7}
|
||||
.dmca-box{background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.08);border-radius:14px;padding:24px;margin-bottom:24px}
|
||||
.dmca-box h3{font-size:.95rem;font-weight:800;margin-bottom:14px;color:rgba(255,255,255,.85)}
|
||||
.dmca-box ol{padding-left:20px}
|
||||
.dmca-box li{font-size:.85rem;color:rgba(255,255,255,.6);line-height:1.8;margin-bottom:6px}
|
||||
.dmca-email{display:inline-block;background:rgba(255,45,125,.12);border:1px solid rgba(255,45,125,.25);border-radius:10px;padding:14px 20px;color:#ff2d7d;font-weight:700;font-size:.9rem;text-decoration:none;margin-top:8px}
|
||||
.legal-updated{font-size:.78rem;color:rgba(255,255,255,.25);text-align:right;margin-bottom:32px}
|
||||
</style>
|
||||
@endpush
|
||||
@section('content')
|
||||
<div style="max-width:1200px;margin:0 auto">
|
||||
|
||||
<div class="legal-hero">
|
||||
<h1>Telif Hakkı & DMCA</h1>
|
||||
<p>İçerik kaldırma talepleri ve telif hakkı politikası</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-body">
|
||||
|
||||
<div class="legal-warn">
|
||||
<p><strong>Önemli:</strong> Animexe herhangi bir video içeriğini sunucularında barındırmaz. Tüm videolar üçüncü taraf platformlara embed edilmektedir. Hak sahiplerinin içerik kaldırma taleplerine en kısa sürede yanıt veririz.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>1. Platform Statüsü — Teknik Aracı</h2>
|
||||
<p>Animexe, <strong>5651 sayılı Kanun</strong> kapsamında bir <strong>yer sağlayıcı</strong> ve teknik aracıdır. Platform:</p>
|
||||
<ul>
|
||||
<li>Video içeriklerini kendi sunucularında <strong>barındırmaz, depolamaz veya yüklemez</strong>.</li>
|
||||
<li>Üçüncü taraf video barındırma platformlarından (YouTube, Dailymotion, Drive vb.) iframe/embed yöntemiyle içerik gösterir.</li>
|
||||
<li>İçeriklerin telif hakkı sahipliği, orijinal barındırma platformlarına aittir.</li>
|
||||
<li>İçerik kaldırma taleplerini alır ve ilgili üçüncü taraflarla koordineli biçimde işler.</li>
|
||||
</ul>
|
||||
<p>Anime içerikleri üzerindeki telif hakları; ilgili Japon yapım şirketlerine, yayıncılarına ve lisans sahiplerine aittir. Animexe bu içerikler üzerinde herhangi bir hak iddia etmez.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>2. Telif Hakkı İhlali Bildirimi (DMCA / 5651)</h2>
|
||||
<p>İçeriğinizin izniniz olmadan Platform'da yayımlandığını düşünüyorsanız aşağıdaki bilgilerle bize ulaşın:</p>
|
||||
|
||||
<div class="dmca-box">
|
||||
<h3>📋 Bildirimde Bulunması Gereken Bilgiler</h3>
|
||||
<ol>
|
||||
<li>Hak sahibinin (veya yetkili temsilcinin) <strong>adı, soyadı ve iletişim bilgileri</strong></li>
|
||||
<li>Telif hakkı ihlali iddia edilen <strong>orijinal eserin tanımı</strong></li>
|
||||
<li>Kaldırılmasını talep ettiğiniz <strong>Platform üzerindeki içeriğin tam URL'si</strong></li>
|
||||
<li>Söz konusu kullanımın yasal olarak yetkilendirilmediğine <strong>iyi niyet beyanı</strong></li>
|
||||
<li>Verdiğiniz bilgilerin doğru olduğuna ve hak sahibi ya da yetkili temsilci sıfatıyla hareket ettiğinize dair <strong>beyan</strong></li>
|
||||
<li>İmza (elektronik veya ıslak imza)</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<p>Bildiriminizi şu adrese gönderin:</p>
|
||||
<a class="dmca-email" href="mailto:dmca@animexe.com">
|
||||
✉ dmca@animexe.com
|
||||
</a>
|
||||
<br><br>
|
||||
<p>Geçerli bir bildirim aldıktan sonra ilgili içeriği <strong>en geç 72 saat içinde</strong> kaldırır veya erişimi engelleriz.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>3. Karşı Bildirim (Counter-Notice)</h2>
|
||||
<p>İçeriğinizin hatalı olarak kaldırıldığını düşünüyorsanız karşı bildirimde bulunabilirsiniz. Karşı bildirimde şunlar yer almalıdır:</p>
|
||||
<ul>
|
||||
<li>Kimlik bilgileriniz ve iletişim bilgileriniz</li>
|
||||
<li>Kaldırılan içeriğin açıklaması ve URL'si</li>
|
||||
<li>İçeriğin hatalı kaldırıldığına dair iyi niyet beyanı</li>
|
||||
<li>Verilen bilgilerin doğru olduğuna dair yemin beyanı</li>
|
||||
</ul>
|
||||
<p>Karşı bildirimler orijinal şikâyet sahibine iletilir ve 10 iş günü içinde değerlendirilir.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>4. Tekrarlayan İhlaller Politikası</h2>
|
||||
<p>Birden fazla kez telif hakkı ihlali tespit edilen kullanıcıların hesapları <strong>kalıcı olarak kapatılır</strong>. Platform, bu konuda DMCA tekrarlayan ihlalci politikasına uygun hareket eder.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>5. Hukuki Koruma ve Adil Kullanım</h2>
|
||||
<p>Platform, aşağıdaki ilkeler çerçevesinde hareket ettiğini beyan eder:</p>
|
||||
<ul>
|
||||
<li>ABD hukukunda DMCA Safe Harbor (17 U.S.C. §512), Türk hukukunda 5651 sayılı Kanun kapsamında teknik aracı korumasından yararlanmaktadır.</li>
|
||||
<li>Anime tanıtım görselleri, karakter isimleri ve başlıklar "adil kullanım" (fair use) / tanıtım amacıyla kullanılmakta olup ticari amaç taşımamaktadır.</li>
|
||||
<li>Platform, içeriklerden herhangi bir reklam geliri elde etmemektedir (içerik barındırılmadığından).</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>6. Hukuki Süreç Talepleri</h2>
|
||||
<p>Mahkeme kararı, savcılık müzekkeresi veya resmi hukuki talepleri aşağıdaki adrese iletiniz:</p>
|
||||
<p><a href="mailto:hukuk@animexe.com" style="color:#ff2d7d">hukuk@animexe.com</a></p>
|
||||
<p>Talepler, Türkiye Cumhuriyeti mahkemelerinin yetkisi dahilinde değerlendirilir.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>7. Lisans Talepleri</h2>
|
||||
<p>İçeriklerinizin Platform'da lisanslı ve yasal olarak yayımlanmasını istiyorsanız lisans anlaşması için bizimle iletişime geçin:</p>
|
||||
<p><a href="mailto:lisans@animexe.com" style="color:#ff2d7d">lisans@animexe.com</a></p>
|
||||
</div>
|
||||
|
||||
<div class="legal-updated">Son güncelleme: Nisan 2025 — Animexe Ekibi</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,152 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Gizlilik Politikası | Animexe')
|
||||
@push('styles')
|
||||
<style>
|
||||
.legal-hero{padding-top:calc(var(--nav-h) + 48px);padding-bottom:28px;text-align:center}
|
||||
.legal-hero h1{font-size:1.8rem;font-weight:900;margin-bottom:8px}
|
||||
.legal-hero p{color:rgba(255,255,255,.4);font-size:.9rem}
|
||||
.legal-body{max-width:820px;margin:0 auto;padding:0 20px 80px}
|
||||
.legal-section{margin-bottom:36px}
|
||||
.legal-section h2{font-size:1.05rem;font-weight:800;color:#ff2d7d;margin-bottom:12px;padding-bottom:8px;border-bottom:1px solid rgba(255,255,255,.07)}
|
||||
.legal-section p,.legal-section li{font-size:.88rem;color:rgba(255,255,255,.65);line-height:1.8;margin-bottom:8px}
|
||||
.legal-section ul{padding-left:20px}
|
||||
.legal-section li{margin-bottom:4px}
|
||||
.legal-warn{background:rgba(59,130,246,.07);border:1px solid rgba(59,130,246,.2);border-radius:12px;padding:16px 20px;margin-bottom:32px}
|
||||
.legal-warn p{color:rgba(180,210,255,.7);font-size:.83rem;margin:0;line-height:1.7}
|
||||
.legal-table{width:100%;border-collapse:collapse;font-size:.83rem;margin-bottom:12px}
|
||||
.legal-table th{text-align:left;color:rgba(255,255,255,.4);font-weight:700;padding:8px 12px;border-bottom:1px solid rgba(255,255,255,.07);font-size:.75rem;text-transform:uppercase}
|
||||
.legal-table td{padding:8px 12px;color:rgba(255,255,255,.6);border-bottom:1px solid rgba(255,255,255,.04)}
|
||||
.legal-updated{font-size:.78rem;color:rgba(255,255,255,.25);text-align:right;margin-bottom:32px}
|
||||
</style>
|
||||
@endpush
|
||||
@section('content')
|
||||
<div style="max-width:1200px;margin:0 auto">
|
||||
|
||||
<div class="legal-hero">
|
||||
<h1>Gizlilik Politikası</h1>
|
||||
<p>Son güncelleme: Nisan 2025</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-body">
|
||||
|
||||
<div class="legal-warn">
|
||||
<p><strong>KVKK Bildirimi:</strong> Bu politika, 6698 sayılı Kişisel Verilerin Korunması Kanunu (KVKK) uyarınca hazırlanmıştır. Animexe olarak kişisel verilerinizin korunmasını ciddiye alıyoruz.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>1. Veri Sorumlusu</h2>
|
||||
<p>Animexe platformu kapsamında kişisel verilerinizin işlenmesinden sorumlu veri sorumlusu, <strong>Animexe</strong>'dir. İletişim için: <a href="mailto:iletisim@animexe.com" style="color:#ff2d7d">iletisim@animexe.com</a></p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>2. Topladığımız Veriler</h2>
|
||||
<table class="legal-table">
|
||||
<tr><th>Veri Türü</th><th>Açıklama</th><th>Zorunluluk</th></tr>
|
||||
<tr><td>Hesap Bilgileri</td><td>Ad, kullanıcı adı, e-posta adresi</td><td>Zorunlu</td></tr>
|
||||
<tr><td>Profil Bilgileri</td><td>Profil fotoğrafı, biyografi (isteğe bağlı)</td><td>İsteğe bağlı</td></tr>
|
||||
<tr><td>Aktivite Verileri</td><td>İzleme geçmişi, oy kullanma, yorum yazma, favori listesi</td><td>Otomatik</td></tr>
|
||||
<tr><td>Teknik Veriler</td><td>IP adresi, tarayıcı türü, cihaz bilgisi, çerezler</td><td>Otomatik</td></tr>
|
||||
<tr><td>İletişim Verileri</td><td>Bize gönderdiğiniz mesajlar</td><td>İsteğe bağlı</td></tr>
|
||||
</table>
|
||||
<p>Kredi kartı veya ödeme bilgisi toplamamaktayız.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>3. Verilerin İşlenme Amaçları</h2>
|
||||
<ul>
|
||||
<li>Hesabınızı oluşturmak ve yönetmek</li>
|
||||
<li>Kişiselleştirilmiş içerik ve öneri sunmak (Ruh Hali Motoru vb.)</li>
|
||||
<li>Kullanıcı güvenliğini sağlamak ve yetkisiz erişimi önlemek</li>
|
||||
<li>Platform hizmetlerini geliştirmek ve teknik sorunları gidermek</li>
|
||||
<li>İstatistiksel analiz yapmak (anonim ve toplu hâlde)</li>
|
||||
<li>Hukuki yükümlülükleri yerine getirmek</li>
|
||||
<li>Hizmet bildirimleri göndermek (e-posta onayı, şifre sıfırlama vb.)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>4. Hukuki İşleme Dayanakları (KVKK md. 5)</h2>
|
||||
<ul>
|
||||
<li><strong>Sözleşme ifası:</strong> Hesap oluşturma ve platform hizmetlerinin sunulması için zorunlu veriler</li>
|
||||
<li><strong>Meşru menfaat:</strong> Platform güvenliği, dolandırıcılık önleme, analitik</li>
|
||||
<li><strong>Açık rıza:</strong> Pazarlama iletişimleri ve isteğe bağlı özellikler</li>
|
||||
<li><strong>Hukuki yükümlülük:</strong> Resmi makam talepleri ve yasal gereklilikler</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>5. Verilerin Paylaşılması</h2>
|
||||
<p>Kişisel verilerinizi aşağıdaki durumlar dışında üçüncü taraflarla satmaz veya kiralamayız:</p>
|
||||
<ul>
|
||||
<li><strong>Teknik hizmet sağlayıcılar:</strong> Sunucu barındırma, e-posta servisi gibi altyapı hizmetleri (işleme sözleşmesi kapsamında)</li>
|
||||
<li><strong>Yasal zorunluluklar:</strong> Yetkili kamu kurum ve kuruluşlarının talepleri</li>
|
||||
<li><strong>Platform güvenliği:</strong> Dolandırıcılık veya yasadışı faaliyetin tespiti halinde ilgili makamlarla paylaşım</li>
|
||||
</ul>
|
||||
<p>Üçüncü taraf embed içerik sağlayıcıları (video platformları) kendi gizlilik politikalarına tabidir; bu politikalar üzerinde kontrolümüz bulunmamaktadır.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>6. Çerezler (Cookies)</h2>
|
||||
<p>Platform, aşağıdaki amaçlarla çerezler kullanmaktadır:</p>
|
||||
<ul>
|
||||
<li><strong>Zorunlu çerezler:</strong> Oturum yönetimi, CSRF koruması — devre dışı bırakılamaz</li>
|
||||
<li><strong>Tercih çerezleri:</strong> Dil, tema ve kullanıcı tercihleri</li>
|
||||
<li><strong>Analitik çerezler:</strong> Anonim kullanım istatistikleri</li>
|
||||
</ul>
|
||||
<p>Tarayıcı ayarlarından çerezleri yönetebilirsiniz. Zorunlu çerezleri reddetmek Platform'un düzgün çalışmasını engelleyebilir.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>7. Veri Saklama Süreleri</h2>
|
||||
<ul>
|
||||
<li>Aktif hesap verileri: Hesap silinene kadar</li>
|
||||
<li>Hesap silindikten sonra: 30 gün içinde kalıcı silme</li>
|
||||
<li>Yasal zorunluluk gerektiren veriler: İlgili mevzuatta öngörülen süre (genellikle 3–10 yıl)</li>
|
||||
<li>Anonimleştirilmiş analitik veriler: Süresiz (kişisel veri içermediğinden)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>8. Veri Güvenliği</h2>
|
||||
<p>Kişisel verilerinizi korumak için aşağıdaki teknik ve idari önlemleri alıyoruz:</p>
|
||||
<ul>
|
||||
<li>HTTPS (SSL/TLS) şifrelemesi</li>
|
||||
<li>Şifreler bcrypt/hash ile saklanır; hiçbir zaman düz metin olarak tutulmaz</li>
|
||||
<li>Veritabanı erişimini kısıtlayan güvenlik duvarları</li>
|
||||
<li>Düzenli güvenlik güncellemeleri ve yama uygulaması</li>
|
||||
<li>Çalışan erişim kontrolü (need-to-know prensibi)</li>
|
||||
</ul>
|
||||
<p>Hiçbir sistem %100 güvenli değildir. Güvenlik ihlali tespit edilmesi halinde sizi ve ilgili makamları KVKK'nın öngördüğü süre içinde (72 saat) bilgilendiririz.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>9. KVKK Kapsamındaki Haklarınız</h2>
|
||||
<p>KVKK'nın 11. maddesi uyarınca aşağıdaki haklara sahipsiniz:</p>
|
||||
<ul>
|
||||
<li>Kişisel verilerinizin işlenip işlenmediğini öğrenme</li>
|
||||
<li>İşlenmişse buna ilişkin bilgi talep etme</li>
|
||||
<li>İşlenme amacını ve bunların amacına uygun kullanılıp kullanılmadığını öğrenme</li>
|
||||
<li>Yurt içinde veya yurt dışında kişisel verilerin aktarıldığı üçüncü kişileri bilme</li>
|
||||
<li>Kişisel verilerin eksik veya yanlış işlenmiş olması hâlinde bunların düzeltilmesini isteme</li>
|
||||
<li>Verilerin silinmesini veya yok edilmesini isteme (yasal sınırlar çerçevesinde)</li>
|
||||
<li>İşlenen verilerin münhasıran otomatik sistemler vasıtasıyla analiz edilmesi suretiyle aleyhinize bir sonucun ortaya çıkmasına itiraz etme</li>
|
||||
<li>Kişisel verilerin kanuna aykırı olarak işlenmesi sebebiyle zarara uğraması hâlinde zararın giderilmesini talep etme</li>
|
||||
</ul>
|
||||
<p>Bu haklarınızı kullanmak için <a href="mailto:iletisim@animexe.com" style="color:#ff2d7d">iletisim@animexe.com</a> adresine e-posta gönderin. Talepler 30 gün içinde yanıtlanır.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>10. Politika Değişiklikleri</h2>
|
||||
<p>Bu politikayı zaman zaman güncelleyebiliriz. Önemli değişiklikler için kayıtlı e-posta adresinize bildirim göndeririz. Değişikliği kabul etmiyorsanız hesabınızı silebilirsiniz.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>11. Şikâyet Hakkı</h2>
|
||||
<p>Kişisel verilerinizin işlenmesiyle ilgili şikayetleriniz için <strong>Kişisel Verileri Koruma Kurumu</strong>'na (KVKK) başvurabilirsiniz: <a href="https://www.kvkk.gov.tr" target="_blank" rel="noopener" style="color:#ff2d7d">www.kvkk.gov.tr</a></p>
|
||||
</div>
|
||||
|
||||
<div class="legal-updated">Son güncelleme: Nisan 2025 — Animexe Ekibi</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,141 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Kullanım Koşulları | Animexe')
|
||||
@push('styles')
|
||||
<style>
|
||||
.legal-hero{padding-top:calc(var(--nav-h) + 48px);padding-bottom:28px;text-align:center}
|
||||
.legal-hero h1{font-size:1.8rem;font-weight:900;margin-bottom:8px}
|
||||
.legal-hero p{color:rgba(255,255,255,.4);font-size:.9rem}
|
||||
.legal-body{max-width:820px;margin:0 auto;padding:0 20px 80px}
|
||||
.legal-section{margin-bottom:36px}
|
||||
.legal-section h2{font-size:1.05rem;font-weight:800;color:#ff2d7d;margin-bottom:12px;padding-bottom:8px;border-bottom:1px solid rgba(255,255,255,.07)}
|
||||
.legal-section p,.legal-section li{font-size:.88rem;color:rgba(255,255,255,.65);line-height:1.8;margin-bottom:8px}
|
||||
.legal-section ul{padding-left:20px}
|
||||
.legal-section li{margin-bottom:4px}
|
||||
.legal-warn{background:rgba(255,45,125,.07);border:1px solid rgba(255,45,125,.2);border-radius:12px;padding:16px 20px;margin-bottom:32px}
|
||||
.legal-warn p{color:rgba(255,200,200,.7);font-size:.83rem;margin:0;line-height:1.7}
|
||||
.legal-updated{font-size:.78rem;color:rgba(255,255,255,.25);text-align:right;margin-bottom:32px}
|
||||
</style>
|
||||
@endpush
|
||||
@section('content')
|
||||
<div style="max-width:1200px;margin:0 auto">
|
||||
|
||||
<div class="legal-hero">
|
||||
<h1>Kullanım Koşulları</h1>
|
||||
<p>Son güncelleme: Nisan 2025</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-body">
|
||||
|
||||
<div class="legal-warn">
|
||||
<p><strong>Önemli:</strong> Bu platformu kullanarak aşağıdaki koşulların tamamını okuduğunuzu, anladığınızı ve kabul ettiğinizi beyan etmiş olursunuz. Koşulları kabul etmiyorsanız lütfen platformu kullanmayınız.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>1. Genel Bilgiler ve Platform Statüsü</h2>
|
||||
<p>Animexe ("Platform", "Biz", "Site"), yalnızca <strong>tanıtım, eğitim ve araştırma amaçlı</strong> olarak tasarlanmış bir anime topluluğu ve içerik tanıtım platformudur. Platform, kullanıcılara anime hakkında bilgi, tartışma, yorum ve topluluğa dayalı özellikler sunmaktadır.</p>
|
||||
<p>Platform, herhangi bir video içeriğini barındırmaz, depolamaz veya dağıtmaz. Gösterilen içerikler üçüncü taraf kaynaklardan embed yoluyla sunulmakta olup Platform yalnızca teknik bir aracı konumundadır.</p>
|
||||
<p>Platform, 18 yaş ve üzeri kullanıcılara yönelik olup bazı içerikler yetişkin temalı unsurlar içerebilir. 18 yaşın altındaki kullanıcılar platformu kullanmamalıdır.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>2. Sorumluluk Reddi — İçerik</h2>
|
||||
<ul>
|
||||
<li>Platform, üçüncü taraflarca üretilen veya barındırılan içeriklerden <strong>hiçbir şekilde sorumlu değildir</strong>.</li>
|
||||
<li>Embed edilen videolar, resimler veya diğer medya içerikleri ilgili üçüncü taraf platformlara (örn. Google Drive, Dailymotion, Streamtape, vb.) aittir.</li>
|
||||
<li>Platform, üçüncü taraf içeriklerinin doğruluğunu, güncelliğini veya yasallığını garanti etmez.</li>
|
||||
<li>Herhangi bir içeriğin telif hakkı ihlali oluşturduğunu düşünüyorsanız lütfen <a href="{{ route('legal.dmca') }}" style="color:#ff2d7d">Telif Hakkı Bildirimi</a> sayfamızı ziyaret edin.</li>
|
||||
<li>Platform, yalnızca teknik altyapı sağlayan bir aracı niteliğinde olup 5651 sayılı Kanun kapsamında içerik sağlayıcı değil, <strong>yer sağlayıcı</strong> konumundadır.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>3. Kullanıcı Hesabı ve Sorumlulukları</h2>
|
||||
<ul>
|
||||
<li>Kayıt olurken gerçek ve güncel bilgi sağlamak zorundasınız. Yanlış bilgi vermek hesabın askıya alınmasına yol açabilir.</li>
|
||||
<li>Hesap şifrenizin güvenliğinden siz sorumlusunuz. Hesabınızın yetkisiz kullanımını derhal bize bildirmeniz gerekmektedir.</li>
|
||||
<li>Bir kullanıcı, yalnızca bir hesap açabilir. Çoklu hesap açmak yasaktır.</li>
|
||||
<li>Hesabınızı başkasına devredemez veya satamazsınız.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>4. Yasaklı Kullanımlar</h2>
|
||||
<p>Aşağıdaki eylemler kesinlikle yasaktır:</p>
|
||||
<ul>
|
||||
<li>Platform altyapısına zarar verecek saldırılar (DDoS, SQL injection, XSS vb.) gerçekleştirmek</li>
|
||||
<li>Otomatik bot, scraper veya benzeri araçlarla Platform'a erişmek</li>
|
||||
<li>Diğer kullanıcılara yönelik taciz, nefret söylemi, tehdit veya ayrımcılık içeren içerik paylaşmak</li>
|
||||
<li>Gerçek kişilerin kişisel bilgilerini izinsiz olarak paylaşmak (doxing)</li>
|
||||
<li>Yasadışı faaliyetleri teşvik eden içerik paylaşmak</li>
|
||||
<li>Platform'un ticari amaçlarla yetkisiz kullanımı</li>
|
||||
<li>Spam, yanıltıcı veya aldatıcı içerik paylaşmak</li>
|
||||
<li>Reşit olmayan bireyleri içeren müstehcen içerik paylaşmak veya yüklemeye teşebbüs etmek</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>5. Kullanıcı Tarafından Oluşturulan İçerik (UGC)</h2>
|
||||
<p>Platform'a yorum, argüman, kapsül mesajı veya diğer içerikler gönderdiğinizde:</p>
|
||||
<ul>
|
||||
<li>Bu içeriklerin yasalara uygun, doğru ve başkalarının haklarına saygılı olduğunu beyan edersiniz.</li>
|
||||
<li>Platform'a, içeriği görüntüleme, depolama ve kullanıcılara sunma için <strong>gayri münhasır, ücretsiz bir lisans</strong> verirsiniz.</li>
|
||||
<li>Üçüncü tarafların telif hakları, ticari markaları veya özel haklarını ihlal eden içerik paylaşmaktan siz sorumlusunuz.</li>
|
||||
<li>Platform, herhangi bir içeriği önceden haber vermeksizin kaldırma hakkını saklı tutar.</li>
|
||||
<li>Spoiler tespiti dahil her türlü içerik moderasyonu otomatik sistemler ve/veya editörler tarafından yapılabilir; Platform bu kararların kesin doğruluğunu garanti etmez.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>6. Fikri Mülkiyet</h2>
|
||||
<p>Platform'un özgün tasarımı, logosu, kodu ve içerikleri Animexe'ye aittir ve Türk Fikir ve Sanat Eserleri Kanunu kapsamında koruma altındadır.</p>
|
||||
<p>Anime adları, görseller, karakterler ve ilgili materyaller kendi telif hakkı sahiplerine (Japon stüdyolar, yayıncılar vb.) aittir. Bu içeriklerin kullanımı yalnızca tanıtım amacıyla "adil kullanım" ilkesi çerçevesinde gerçekleşmektedir.</p>
|
||||
<p>Platform içeriğini izinsiz kopyalamak, dağıtmak veya ticari amaçla kullanmak yasaktır.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>7. Hesap Askıya Alma ve Sonlandırma</h2>
|
||||
<p>Platform, aşağıdaki durumlarda hesabınızı önceden haber vermeksizin askıya alabilir veya silebilir:</p>
|
||||
<ul>
|
||||
<li>Bu Koşullar'ın ihlali</li>
|
||||
<li>Hukuki bir gereklilik veya resmi makam talebi</li>
|
||||
<li>Diğer kullanıcılara veya platforma zarar veren davranışlar</li>
|
||||
<li>Uzun süreli hesap hareketsizliği (12 ay ve üzeri)</li>
|
||||
</ul>
|
||||
<p>Hesabınızı kendiniz silmek istediğinizde tüm verileriniz 30 gün içinde kalıcı olarak silinir.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>8. Hizmetin Değiştirilmesi ve Sonlandırılması</h2>
|
||||
<p>Platform, herhangi bir zamanda ve önceden bildirimde bulunmaksızın hizmetini, özelliklerini veya bu Koşulları değiştirme hakkını saklı tutar. Değişiklikler yayımlandıktan sonra platformu kullanmaya devam etmeniz yeni koşulları kabul ettiğiniz anlamına gelir.</p>
|
||||
<p>Platform, teknik arıza, bakım veya mücbir sebep nedeniyle hizmetini geçici ya da kalıcı olarak durdurabilir. Bu durumdan doğan hiçbir zarardan sorumlu tutulamaz.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>9. Sorumluluk Sınırlaması</h2>
|
||||
<p>Platform, aşağıdaki durumlardan kaynaklanan zararlardan sorumlu değildir:</p>
|
||||
<ul>
|
||||
<li>Üçüncü taraf içeriklere erişimden veya bu içeriklere güvenmekten kaynaklanan zararlar</li>
|
||||
<li>Hizmet kesintisi veya veri kaybı</li>
|
||||
<li>Kullanıcılar arasındaki anlaşmazlıklar</li>
|
||||
<li>Yetkisiz hesap erişimi (kullanıcı güvenlik ihlalinden kaynaklanıyorsa)</li>
|
||||
<li>Üçüncü taraf site veya hizmetlerinin kullanımı</li>
|
||||
</ul>
|
||||
<p>Platformun toplam sorumluluğu, varsa ödenen üyelik ücretini geçemez.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>10. Uygulanacak Hukuk ve Uyuşmazlık Çözümü</h2>
|
||||
<p>Bu Koşullar, <strong>Türkiye Cumhuriyeti</strong> hukukuna tabidir. Bu Koşullar'dan doğan uyuşmazlıkların çözümünde <strong>Türkiye Cumhuriyeti mahkemeleri</strong> yetkilidir.</p>
|
||||
<p>Herhangi bir anlaşmazlık için öncelikle <a href="mailto:iletisim@animexe.com" style="color:#ff2d7d">iletisim@animexe.com</a> adresine başvurulması tavsiye edilir.</p>
|
||||
</div>
|
||||
|
||||
<div class="legal-section">
|
||||
<h2>11. İletişim</h2>
|
||||
<p>Kullanım Koşulları hakkında sorularınız için: <a href="mailto:iletisim@animexe.com" style="color:#ff2d7d">iletisim@animexe.com</a></p>
|
||||
</div>
|
||||
|
||||
<div class="legal-updated">Son güncelleme: Nisan 2025 — Animexe Ekibi</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,103 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Mesajlar — Animexe')
|
||||
@push('styles')
|
||||
<style>
|
||||
.msg-wrap{max-width:680px;margin:0 auto;padding:calc(var(--nav-h) + 28px) 16px 64px}
|
||||
.msg-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:20px}
|
||||
.msg-header h1{font-size:1.3rem;font-weight:900;color:#fff}
|
||||
|
||||
.msg-list{display:flex;flex-direction:column;gap:4px}
|
||||
.msg-row{
|
||||
display:flex;align-items:center;gap:14px;
|
||||
padding:14px 16px;border-radius:14px;
|
||||
background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.06);
|
||||
text-decoration:none;transition:all .15s;cursor:pointer;
|
||||
}
|
||||
.msg-row:hover{background:rgba(255,255,255,.06);border-color:rgba(255,255,255,.12)}
|
||||
.msg-row.unread{background:rgba(0,245,255,.04);border-color:rgba(0,245,255,.12)}
|
||||
|
||||
.msg-ava{
|
||||
width:46px;height:46px;border-radius:50%;flex-shrink:0;overflow:hidden;
|
||||
background:linear-gradient(135deg,var(--accent2),var(--accent));
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
font-size:1.1rem;font-weight:800;color:#fff;
|
||||
}
|
||||
.msg-ava img{width:100%;height:100%;object-fit:cover}
|
||||
|
||||
.msg-info{flex:1;min-width:0}
|
||||
.msg-name{font-size:.9rem;font-weight:700;color:#fff;margin-bottom:3px;display:flex;align-items:center;gap:8px}
|
||||
.msg-preview{font-size:.8rem;color:rgba(255,255,255,.4);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||
.msg-row.unread .msg-preview{color:rgba(255,255,255,.7)}
|
||||
.msg-unread-dot{width:8px;height:8px;border-radius:50%;background:var(--accent2);flex-shrink:0}
|
||||
.msg-time{font-size:.7rem;color:rgba(255,255,255,.25);flex-shrink:0;align-self:flex-start;margin-top:4px}
|
||||
|
||||
.msg-empty{text-align:center;padding:64px 20px;color:rgba(255,255,255,.2)}
|
||||
.msg-empty i{font-size:2.8rem;display:block;margin-bottom:14px;opacity:.2}
|
||||
.msg-empty p{font-size:.9rem}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="msg-wrap">
|
||||
<div class="msg-header">
|
||||
<h1><i class="bi bi-chat-dots" style="color:var(--accent2)"></i> Mesajlar</h1>
|
||||
</div>
|
||||
|
||||
@if($conversations->isEmpty())
|
||||
<div class="msg-empty">
|
||||
<i class="bi bi-chat-square-dots"></i>
|
||||
<p>Henüz mesajın yok.<br>Bir kullanıcının profiline git ve mesaj gönder.</p>
|
||||
</div>
|
||||
@else
|
||||
<div class="msg-list">
|
||||
@foreach($conversations as $conv)
|
||||
@php
|
||||
$other = $conv['other'];
|
||||
$last = $conv['last_message'];
|
||||
$unread= $conv['unread'];
|
||||
@endphp
|
||||
<a href="{{ route('messages.show', $conv['id']) }}" class="msg-row {{ $unread > 0 ? 'unread' : '' }}">
|
||||
<div class="msg-ava">
|
||||
@if($other?->avatar)
|
||||
<img src="{{ \App\Support\MediaUrl::fromStoragePath($other->avatar) }}" alt="{{ $other->name }}">
|
||||
@else
|
||||
{{ mb_strtoupper(mb_substr($other?->name ?? '?', 0, 1)) }}
|
||||
@endif
|
||||
</div>
|
||||
<div class="msg-info">
|
||||
<div class="msg-name">
|
||||
{{ $other?->name ?? 'Silinmiş Kullanıcı' }}
|
||||
@if($unread > 0)
|
||||
<span style="font-size:.65rem;background:var(--accent2);color:#05050e;padding:1px 7px;border-radius:20px;font-weight:800">{{ $unread }}</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="msg-preview">
|
||||
@if($last)
|
||||
@if($last->user_id === auth()->id()) <span style="color:rgba(255,255,255,.25)">Sen: </span> @endif
|
||||
@if(str_starts_with($last->body, 'ANIMESHARE::'))
|
||||
@php try { $sd = json_decode(substr($last->body,12),true); } catch(\Throwable $e){ $sd=null; } @endphp
|
||||
<i class="bi bi-play-circle" style="color:var(--accent2)"></i> {{ $sd['title'] ?? 'Anime' }} paylaştı
|
||||
@elseif(str_starts_with($last->body, 'IMAGE::'))
|
||||
<i class="bi bi-image"></i> Fotoğraf
|
||||
@elseif(str_starts_with($last->body, 'GIF::'))
|
||||
<i class="bi bi-file-play"></i> GIF
|
||||
@else
|
||||
{{ Str::limit($last->body, 60) }}
|
||||
@endif
|
||||
@else
|
||||
<em>Henüz mesaj yok</em>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;flex-direction:column;align-items:flex-end;gap:6px">
|
||||
@if($unread > 0)<div class="msg-unread-dot"></div>@endif
|
||||
<span class="msg-time">
|
||||
@if($conv['updated_at']){{ $conv['updated_at']->diffForHumans(null, true) }}@endif
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,655 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', ($other?->name ?? 'Mesaj') . ' — Animexe')
|
||||
@push('styles')
|
||||
<style>
|
||||
footer{display:none!important}
|
||||
#page-content{padding:0!important}
|
||||
#ai-fab,#ai-panel{display:none!important}
|
||||
#topnav,#mob-bottom-nav{display:none!important}
|
||||
.w-chat-support{display:none!important}
|
||||
|
||||
.chat-root{
|
||||
display:flex;flex-direction:column;
|
||||
position:fixed;
|
||||
top:0;left:0;right:0;bottom:0;
|
||||
background:#05050e;
|
||||
}
|
||||
|
||||
/* ── Header ─────────────────────────────── */
|
||||
.chat-hdr{
|
||||
display:flex;align-items:center;gap:10px;
|
||||
padding:10px 14px;
|
||||
background:rgba(5,5,14,.95);backdrop-filter:blur(12px);
|
||||
border-bottom:1px solid rgba(255,255,255,.07);
|
||||
flex-shrink:0;z-index:10;
|
||||
}
|
||||
.chat-hdr-back{
|
||||
width:36px;height:36px;border-radius:10px;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
background:rgba(255,255,255,.06);border:none;
|
||||
color:rgba(255,255,255,.6);font-size:1rem;cursor:pointer;
|
||||
text-decoration:none;flex-shrink:0;transition:all .15s;
|
||||
}
|
||||
.chat-hdr-back:hover{background:rgba(255,255,255,.12);color:#fff}
|
||||
.chat-hdr-ava{
|
||||
width:38px;height:38px;border-radius:50%;overflow:hidden;flex-shrink:0;
|
||||
background:linear-gradient(135deg,var(--accent2),var(--accent));
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
font-size:.9rem;font-weight:800;color:#fff;text-decoration:none;
|
||||
}
|
||||
.chat-hdr-ava img{width:100%;height:100%;object-fit:cover}
|
||||
.chat-hdr-info{flex:1;min-width:0}
|
||||
.chat-hdr-name{font-size:.9rem;font-weight:800;color:#fff;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||
.chat-hdr-sub{font-size:.68rem;color:rgba(255,255,255,.3)}
|
||||
.chat-hdr-btn{
|
||||
width:36px;height:36px;border-radius:10px;flex-shrink:0;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
background:rgba(255,255,255,.06);border:none;color:rgba(255,255,255,.5);
|
||||
font-size:.9rem;cursor:pointer;text-decoration:none;transition:all .15s;
|
||||
}
|
||||
.chat-hdr-btn:hover{background:rgba(255,255,255,.12);color:#fff}
|
||||
.chat-hdr-btn.call{color:#22c55e}
|
||||
.chat-hdr-btn.call:hover{background:rgba(34,197,94,.15);color:#22c55e}
|
||||
|
||||
/* ── Messages area ──────────────────────── */
|
||||
.chat-body{
|
||||
flex:1;overflow-y:auto;
|
||||
padding:14px 14px 8px;
|
||||
display:flex;flex-direction:column;
|
||||
gap:4px;
|
||||
-webkit-overflow-scrolling:touch;
|
||||
min-height:0;
|
||||
}
|
||||
.chat-body::-webkit-scrollbar{width:3px}
|
||||
.chat-body::-webkit-scrollbar-thumb{background:rgba(255,255,255,.1);border-radius:2px}
|
||||
|
||||
/* ── Bubbles ────────────────────────────── */
|
||||
.chat-msg{display:flex;gap:8px;max-width:80%;align-items:flex-end}
|
||||
.chat-msg.mine{align-self:flex-end;flex-direction:row-reverse}
|
||||
.chat-msg.theirs{align-self:flex-start}
|
||||
.chat-msg-ava{
|
||||
width:28px;height:28px;border-radius:50%;overflow:hidden;flex-shrink:0;
|
||||
background:linear-gradient(135deg,var(--accent2),var(--accent));
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
font-size:.65rem;font-weight:800;color:#fff;
|
||||
}
|
||||
.chat-msg-ava img{width:100%;height:100%;object-fit:cover}
|
||||
.chat-msg.mine .chat-msg-ava{display:none}
|
||||
.chat-bubble{
|
||||
padding:9px 14px;border-radius:18px;
|
||||
font-size:.88rem;line-height:1.5;word-break:break-word;max-width:100%;
|
||||
}
|
||||
.chat-msg.mine .chat-bubble{
|
||||
background:var(--accent2);color:#05050e;font-weight:500;border-bottom-right-radius:5px;
|
||||
}
|
||||
.chat-msg.theirs .chat-bubble{
|
||||
background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.08);
|
||||
color:rgba(255,255,255,.9);border-bottom-left-radius:5px;
|
||||
}
|
||||
.chat-time{font-size:.6rem;color:rgba(255,255,255,.25);align-self:flex-end;margin-bottom:3px;flex-shrink:0}
|
||||
.chat-date-sep{
|
||||
text-align:center;font-size:.65rem;color:rgba(255,255,255,.2);
|
||||
padding:12px 0 4px;font-weight:600;letter-spacing:.08em;
|
||||
}
|
||||
|
||||
/* ── Media messages ─────────────────────── */
|
||||
.chat-img{
|
||||
max-width:220px;max-height:220px;border-radius:14px;
|
||||
cursor:pointer;display:block;object-fit:cover;
|
||||
transition:opacity .15s;border:1px solid rgba(255,255,255,.08);
|
||||
}
|
||||
.chat-img:hover{opacity:.88}
|
||||
.chat-gif{max-width:220px;border-radius:14px;display:block}
|
||||
|
||||
/* ── Share card ─────────────────────────── */
|
||||
.share-card{
|
||||
display:flex;gap:10px;align-items:flex-start;
|
||||
background:rgba(0,245,255,.06);border:1px solid rgba(0,245,255,.18);
|
||||
border-radius:14px;padding:10px 12px;text-decoration:none;
|
||||
max-width:260px;transition:all .15s;
|
||||
}
|
||||
.share-card:hover{background:rgba(0,245,255,.12);border-color:rgba(0,245,255,.35)}
|
||||
.share-card-img{width:54px;height:78px;border-radius:8px;overflow:hidden;flex-shrink:0;background:rgba(255,255,255,.05)}
|
||||
.share-card-img img{width:100%;height:100%;object-fit:cover;display:block}
|
||||
.share-card-label{font-size:.58rem;color:var(--accent2);font-weight:700;letter-spacing:.08em;text-transform:uppercase;margin-bottom:4px}
|
||||
.share-card-title{font-size:.8rem;font-weight:800;color:#fff;line-height:1.3;margin-bottom:3px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
|
||||
.share-card-ep{font-size:.7rem;color:rgba(255,255,255,.5);margin-bottom:3px}
|
||||
.share-card-play{font-size:.68rem;color:var(--accent2);display:flex;align-items:center;gap:3px;margin-top:4px;font-weight:700}
|
||||
|
||||
/* ── Footer input ───────────────────────── */
|
||||
.chat-footer{
|
||||
padding:8px 10px;
|
||||
background:rgba(5,5,14,.95);backdrop-filter:blur(12px);
|
||||
border-top:1px solid rgba(255,255,255,.07);
|
||||
flex-shrink:0;
|
||||
padding-bottom:max(8px,env(safe-area-inset-bottom));
|
||||
}
|
||||
.chat-toolbar{
|
||||
display:flex;align-items:center;gap:6px;
|
||||
padding:4px 0 8px;
|
||||
border-bottom:1px solid rgba(255,255,255,.06);
|
||||
margin-bottom:6px;
|
||||
}
|
||||
.chat-tool-btn{
|
||||
width:38px;height:38px;border-radius:10px;border:none;
|
||||
background:rgba(255,255,255,.06);color:rgba(255,255,255,.45);
|
||||
font-size:.88rem;cursor:pointer;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
transition:all .15s;flex-shrink:0;
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
}
|
||||
.chat-tool-btn:hover{background:rgba(255,255,255,.13);color:#fff}
|
||||
.chat-tool-btn.active{background:rgba(0,245,255,.12);color:var(--accent2)}
|
||||
.chat-form{display:flex;align-items:flex-end;gap:8px}
|
||||
.chat-input{
|
||||
flex:1;background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.1);
|
||||
border-radius:20px;padding:10px 16px;color:#fff;font-size:.9rem;font-family:inherit;
|
||||
resize:none;max-height:120px;overflow-y:auto;min-height:42px;
|
||||
line-height:1.4;outline:none;-webkit-appearance:none;transition:border-color .15s;
|
||||
}
|
||||
.chat-input:focus{border-color:rgba(0,245,255,.35)}
|
||||
.chat-input::placeholder{color:rgba(255,255,255,.25)}
|
||||
.chat-send{
|
||||
width:42px;height:42px;border-radius:50%;flex-shrink:0;
|
||||
background:var(--accent2);border:none;color:#05050e;
|
||||
font-size:1rem;cursor:pointer;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
transition:all .15s;-webkit-tap-highlight-color:transparent;
|
||||
}
|
||||
.chat-send:hover{background:#00d4de;transform:scale(1.05)}
|
||||
.chat-send:disabled{opacity:.4;transform:none;cursor:default}
|
||||
|
||||
/* ── Emoji picker ───────────────────────── */
|
||||
#chat-emoji-picker{
|
||||
display:none;flex-wrap:wrap;gap:2px;
|
||||
background:rgba(10,10,22,.98);border:1px solid rgba(255,255,255,.1);
|
||||
border-radius:14px;padding:10px;
|
||||
max-height:180px;overflow-y:auto;margin-bottom:6px;
|
||||
scrollbar-width:thin;
|
||||
}
|
||||
#chat-emoji-picker.show{display:flex}
|
||||
.chat-emoji-btn{
|
||||
font-size:1.3rem;width:36px;height:36px;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
border:none;background:none;cursor:pointer;border-radius:8px;
|
||||
transition:background .12s;-webkit-tap-highlight-color:transparent;
|
||||
}
|
||||
.chat-emoji-btn:hover{background:rgba(255,255,255,.1)}
|
||||
|
||||
/* ── GIF picker ─────────────────────────── */
|
||||
#chat-gif-picker{
|
||||
display:none;
|
||||
background:rgba(10,10,22,.98);border:1px solid rgba(255,255,255,.1);
|
||||
border-radius:14px;padding:8px;margin-bottom:6px;
|
||||
}
|
||||
#chat-gif-picker.show{display:block}
|
||||
.chat-gif-search{
|
||||
width:100%;padding:8px 12px;border-radius:10px;
|
||||
background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.12);
|
||||
color:#fff;font-size:.82rem;font-family:inherit;outline:none;
|
||||
margin-bottom:8px;-webkit-appearance:none;
|
||||
}
|
||||
.chat-gif-search::placeholder{color:rgba(255,255,255,.3)}
|
||||
.chat-gif-grid{
|
||||
display:grid;grid-template-columns:repeat(3,1fr);gap:4px;
|
||||
max-height:160px;overflow-y:auto;
|
||||
}
|
||||
.chat-gif-item{
|
||||
aspect-ratio:1;background:rgba(255,255,255,.05);border-radius:8px;
|
||||
overflow:hidden;cursor:pointer;transition:opacity .15s;
|
||||
}
|
||||
.chat-gif-item:hover{opacity:.8}
|
||||
.chat-gif-item img{width:100%;height:100%;object-fit:cover;display:block}
|
||||
.chat-gif-ph{padding:20px;text-align:center;color:rgba(255,255,255,.25);font-size:.78rem}
|
||||
|
||||
.chat-empty{
|
||||
flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
|
||||
color:rgba(255,255,255,.2);gap:10px;
|
||||
}
|
||||
.chat-empty i{font-size:2.4rem;opacity:.2}
|
||||
.chat-empty p{font-size:.85rem}
|
||||
|
||||
@media(min-width:640px){
|
||||
.chat-root{max-width:760px;left:50%;transform:translateX(-50%)}
|
||||
.chat-msg{max-width:72%}
|
||||
}
|
||||
@media(max-width:640px){
|
||||
.chat-msg{max-width:88%}
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
@php $me = auth()->user(); @endphp
|
||||
<div class="chat-root">
|
||||
|
||||
{{-- Header --}}
|
||||
<div class="chat-hdr">
|
||||
<a href="{{ route('messages.index') }}" class="chat-hdr-back">
|
||||
<i class="bi bi-chevron-left"></i>
|
||||
</a>
|
||||
<a href="{{ $other ? route('user.profile', $other) : '#' }}" class="chat-hdr-ava">
|
||||
@if($other?->avatar)
|
||||
<img src="{{ \App\Support\MediaUrl::fromStoragePath($other->avatar) }}" alt="{{ $other->name }}">
|
||||
@else
|
||||
{{ mb_strtoupper(mb_substr($other?->name ?? '?', 0, 1)) }}
|
||||
@endif
|
||||
</a>
|
||||
<div class="chat-hdr-info">
|
||||
<div class="chat-hdr-name">{{ $other?->name ?? 'Silinmiş Kullanıcı' }}</div>
|
||||
@if($other?->username)
|
||||
<div class="chat-hdr-sub">@php echo '@' . e($other->username); @endphp</div>
|
||||
@endif
|
||||
</div>
|
||||
@if($other)
|
||||
{{-- Sesli arama --}}
|
||||
<button class="chat-hdr-btn call" id="call-btn" data-user-id="{{ $other->id }}" title="Sesli ara">
|
||||
<i class="bi bi-telephone-fill"></i>
|
||||
</button>
|
||||
{{-- Profil --}}
|
||||
<a href="{{ route('user.profile', $other) }}" class="chat-hdr-btn" title="Profil">
|
||||
<i class="bi bi-person"></i>
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Messages --}}
|
||||
<div class="chat-body" id="chat-body">
|
||||
@if($messages->isEmpty())
|
||||
<div class="chat-empty">
|
||||
<i class="bi bi-chat-dots"></i>
|
||||
<p>Henüz mesaj yok. İlk mesajı sen gönder!</p>
|
||||
</div>
|
||||
@else
|
||||
@php $lastDate = null; @endphp
|
||||
@foreach($messages as $msg)
|
||||
@php
|
||||
$msgDate = $msg->created_at->toDateString();
|
||||
$isMine = $msg->user_id === $me->id;
|
||||
@endphp
|
||||
@if($msgDate !== $lastDate)
|
||||
<div class="chat-date-sep">{{ $msg->created_at->translatedFormat('d F Y') }}</div>
|
||||
@php $lastDate = $msgDate; @endphp
|
||||
@endif
|
||||
<div class="chat-msg {{ $isMine ? 'mine' : 'theirs' }}" data-id="{{ $msg->id }}">
|
||||
@if(!$isMine)
|
||||
<div class="chat-msg-ava">
|
||||
@if($msg->user?->avatar)
|
||||
<img src="{{ \App\Support\MediaUrl::fromStoragePath($msg->user->avatar) }}" alt="">
|
||||
@else{{ mb_strtoupper(mb_substr($msg->user?->name ?? '?', 0, 1)) }}@endif
|
||||
</div>
|
||||
@endif
|
||||
<div>
|
||||
@if(str_starts_with($msg->body, 'ANIMESHARE::'))
|
||||
@php try { $sd = json_decode(substr($msg->body,12),true); } catch(\Throwable $e){ $sd=null; } @endphp
|
||||
@if($sd)
|
||||
<a href="{{ url('/watch/'.($sd['slug']??'').'/'.($sd['s']??1).'/'.($sd['e']??1).(($sd['ts']??0)>0?'?t='.$sd['ts']:'')) }}" class="share-card">
|
||||
<div class="share-card-img">
|
||||
@if(!empty($sd['cover']))<img src="{{ $sd['cover'] }}" loading="lazy" alt="">@else<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:rgba(255,255,255,.2);font-size:1.4rem"><i class="bi bi-play-circle"></i></div>@endif
|
||||
</div>
|
||||
<div>
|
||||
<div class="share-card-label"><i class="bi bi-play-fill"></i> Anime Bölümü</div>
|
||||
<div class="share-card-title">{{ $sd['title'] ?? '' }}</div>
|
||||
<div class="share-card-ep">{{ $sd['s'] ?? '' }}. Sezon {{ $sd['e'] ?? '' }}. Bölüm</div>
|
||||
<div class="share-card-play"><i class="bi bi-play-circle-fill"></i> İzle</div>
|
||||
</div>
|
||||
</a>
|
||||
@else
|
||||
<div class="chat-bubble">{{ $msg->body }}</div>
|
||||
@endif
|
||||
@elseif(str_starts_with($msg->body, 'IMAGE::'))
|
||||
<img src="{{ substr($msg->body, 7) }}" class="chat-img" loading="lazy" alt="Resim"
|
||||
onclick="window.open('{{ substr($msg->body, 7) }}','_blank')">
|
||||
@elseif(str_starts_with($msg->body, 'GIF::'))
|
||||
<img src="{{ substr($msg->body, 5) }}" class="chat-gif" loading="lazy" alt="GIF">
|
||||
@else
|
||||
<div class="chat-bubble">{{ $msg->body }}</div>
|
||||
@endif
|
||||
</div>
|
||||
<span class="chat-time">{{ $msg->created_at->format('H:i') }}</span>
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Footer --}}
|
||||
<div class="chat-footer">
|
||||
<div id="chat-emoji-picker"></div>
|
||||
<div id="chat-gif-picker">
|
||||
<input type="text" class="chat-gif-search" id="chat-gif-input" placeholder="GIF ara…">
|
||||
<div class="chat-gif-grid" id="chat-gif-grid">
|
||||
<div class="chat-gif-ph">GIF aramak için yaz</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-toolbar">
|
||||
<button class="chat-tool-btn" id="chat-emoji-btn" title="Emoji" style="display:none">
|
||||
<i class="bi bi-emoji-smile"></i>
|
||||
</button>
|
||||
<button class="chat-tool-btn" id="chat-gif-btn" title="GIF">
|
||||
<span style="font-size:.65rem;font-weight:800;letter-spacing:.03em">GIF</span>
|
||||
</button>
|
||||
<label class="chat-tool-btn" title="Resim gönder" style="cursor:pointer">
|
||||
<i class="bi bi-image"></i>
|
||||
<input type="file" id="chat-img-input" accept="image/*" style="display:none">
|
||||
</label>
|
||||
<div style="flex:1"></div>
|
||||
</div>
|
||||
<div class="chat-form">
|
||||
<textarea class="chat-input" id="chat-input"
|
||||
placeholder="Mesaj yaz..." rows="1" maxlength="2000"
|
||||
autocomplete="off" autocorrect="off"></textarea>
|
||||
<button type="button" class="chat-send" id="chat-send">
|
||||
<i class="bi bi-send-fill"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
// Crisp ve diğer overlay widgetları kapat
|
||||
try { $crisp.push(['do','chat:hide']); } catch(_){}
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
try { $crisp.push(['do','chat:hide']); } catch(_){}
|
||||
// topnav/bottom-nav kesinlikle gizle (layout JS override için)
|
||||
const tn = document.getElementById('topnav');
|
||||
const bn = document.getElementById('mob-bottom-nav');
|
||||
if(tn) tn.style.setProperty('display','none','important');
|
||||
if(bn) bn.style.setProperty('display','none','important');
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
(function(){
|
||||
'use strict';
|
||||
|
||||
const SEND_URL = '{{ route("messages.send", $conversation) }}';
|
||||
const POLL_URL = '{{ route("messages.poll", $conversation) }}';
|
||||
const UPLOAD_URL = '{{ route("messages.upload-image") }}';
|
||||
const TENOR_KEY = '{{ env("TENOR_API_KEY","") }}';
|
||||
const CSRF = document.querySelector('meta[name=csrf-token]')?.content || '';
|
||||
const ME_ID = {{ $me->id }};
|
||||
const MY_AVA = {!! json_encode($me->avatar ? \App\Support\MediaUrl::fromStoragePath($me->avatar) : null) !!};
|
||||
const MY_NAME = {!! json_encode($me->name) !!};
|
||||
const IS_DESKTOP = window.innerWidth >= 640;
|
||||
|
||||
let lastId = {{ $messages->last()?->id ?? 0 }};
|
||||
let polling = null;
|
||||
let emojiOpen = false;
|
||||
let gifOpen = false;
|
||||
let gifTimer = null;
|
||||
|
||||
const chatBody = document.getElementById('chat-body');
|
||||
const inputEl = document.getElementById('chat-input');
|
||||
const sendBtn = document.getElementById('chat-send');
|
||||
|
||||
/* ── Scroll ──────────────────────────────── */
|
||||
function scrollBottom(force = false) {
|
||||
const near = chatBody.scrollHeight - chatBody.scrollTop - chatBody.clientHeight < 160;
|
||||
if (force || near) chatBody.scrollTop = chatBody.scrollHeight;
|
||||
}
|
||||
scrollBottom(true);
|
||||
|
||||
/* ── Input auto-grow ─────────────────────── */
|
||||
inputEl.addEventListener('input', () => {
|
||||
inputEl.style.height = 'auto';
|
||||
inputEl.style.height = Math.min(inputEl.scrollHeight, 120) + 'px';
|
||||
if (inputEl.value) { hideEmoji(); hideGif(); }
|
||||
});
|
||||
inputEl.addEventListener('keydown', e => {
|
||||
if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); doSend(); }
|
||||
});
|
||||
sendBtn.addEventListener('click', doSend);
|
||||
|
||||
/* ── Escape chars ────────────────────────── */
|
||||
function escH(s) {
|
||||
return String(s||'').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||
}
|
||||
|
||||
/* ── Render message body ─────────────────── */
|
||||
function renderBody(body) {
|
||||
if (!body) return '<div class="chat-bubble"></div>';
|
||||
if (body.startsWith('ANIMESHARE::')) {
|
||||
try {
|
||||
const d = JSON.parse(body.slice(12));
|
||||
const url = `/watch/${d.slug}/${d.s}/${d.e}${d.ts>0?'?t='+d.ts:''}`;
|
||||
const img = d.cover
|
||||
? `<img src="${escH(d.cover)}" loading="lazy" alt="">`
|
||||
: `<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:rgba(255,255,255,.2)"><i class="bi bi-play-circle" style="font-size:1.4rem"></i></div>`;
|
||||
return `<a href="${escH(url)}" class="share-card">
|
||||
<div class="share-card-img">${img}</div>
|
||||
<div>
|
||||
<div class="share-card-label"><i class="bi bi-play-fill"></i> Anime Bölümü</div>
|
||||
<div class="share-card-title">${escH(d.title||'')}</div>
|
||||
<div class="share-card-ep">${escH(String(d.s))}. Sezon ${escH(String(d.e))}. Bölüm</div>
|
||||
<div class="share-card-play"><i class="bi bi-play-circle-fill"></i> İzle</div>
|
||||
</div>
|
||||
</a>`;
|
||||
} catch(_) {}
|
||||
}
|
||||
if (body.startsWith('IMAGE::')) {
|
||||
const url = escH(body.slice(7));
|
||||
return `<img src="${url}" class="chat-img" loading="lazy" alt="Resim" onclick="window.open('${url}','_blank')">`;
|
||||
}
|
||||
if (body.startsWith('GIF::')) {
|
||||
return `<img src="${escH(body.slice(5))}" class="chat-gif" loading="lazy" alt="GIF">`;
|
||||
}
|
||||
return `<div class="chat-bubble">${escH(body)}</div>`;
|
||||
}
|
||||
|
||||
/* ── Append message to DOM ───────────────── */
|
||||
function appendMsg(id, body, isMine, time, avatar, name) {
|
||||
if (document.querySelector(`.chat-msg[data-id="${id}"]`)) return;
|
||||
document.querySelector('.chat-empty')?.remove();
|
||||
|
||||
const wrap = document.createElement('div');
|
||||
wrap.className = 'chat-msg ' + (isMine ? 'mine' : 'theirs');
|
||||
wrap.dataset.id = id;
|
||||
|
||||
let ava = '';
|
||||
if (!isMine) {
|
||||
ava = avatar
|
||||
? `<div class="chat-msg-ava"><img src="${escH(avatar)}" alt=""></div>`
|
||||
: `<div class="chat-msg-ava">${escH((name||'?').charAt(0).toUpperCase())}</div>`;
|
||||
}
|
||||
wrap.innerHTML = ava + `<div>${renderBody(body)}</div><span class="chat-time">${escH(time)}</span>`;
|
||||
chatBody.appendChild(wrap);
|
||||
scrollBottom();
|
||||
}
|
||||
|
||||
/* ── Send text ───────────────────────────── */
|
||||
async function doSend() {
|
||||
const text = inputEl.value.trim();
|
||||
if (!text) return;
|
||||
sendBtn.disabled = true;
|
||||
inputEl.value = '';
|
||||
inputEl.style.height = 'auto';
|
||||
|
||||
try {
|
||||
const res = await fetch(SEND_URL, {
|
||||
method: 'POST',
|
||||
headers: {'X-CSRF-TOKEN': CSRF, 'Accept': 'application/json', 'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({ body: text }),
|
||||
});
|
||||
if (!res.ok) throw new Error();
|
||||
const d = await res.json();
|
||||
appendMsg(d.id, d.body, true, d.created_at, MY_AVA, MY_NAME);
|
||||
if (d.id > lastId) lastId = d.id;
|
||||
scrollBottom(true);
|
||||
} catch(e) {
|
||||
inputEl.value = text;
|
||||
}
|
||||
sendBtn.disabled = false;
|
||||
inputEl.focus();
|
||||
}
|
||||
|
||||
/* ── Send image ──────────────────────────── */
|
||||
document.getElementById('chat-img-input')?.addEventListener('change', async function() {
|
||||
const file = this.files[0];
|
||||
if (!file) return;
|
||||
this.value = '';
|
||||
try {
|
||||
const fd = new FormData();
|
||||
fd.append('image', file);
|
||||
const r = await fetch(UPLOAD_URL, {
|
||||
method: 'POST',
|
||||
headers: {'X-CSRF-TOKEN': CSRF, 'Accept': 'application/json'},
|
||||
body: fd,
|
||||
});
|
||||
const d = await r.json();
|
||||
if (!d.url) throw new Error();
|
||||
const r2 = await fetch(SEND_URL, {
|
||||
method: 'POST',
|
||||
headers: {'X-CSRF-TOKEN': CSRF, 'Accept': 'application/json', 'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({ body: 'IMAGE::' + d.url }),
|
||||
});
|
||||
const d2 = await r2.json();
|
||||
appendMsg(d2.id, d2.body, true, d2.created_at, MY_AVA, MY_NAME);
|
||||
if (d2.id > lastId) lastId = d2.id;
|
||||
scrollBottom(true);
|
||||
} catch(e) {
|
||||
if (window.showToast) showToast('Resim gönderilemedi.', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
/* ── Send GIF ────────────────────────────── */
|
||||
window.chatSendGif = async function(gifUrl) {
|
||||
hideGif();
|
||||
try {
|
||||
const r = await fetch(SEND_URL, {
|
||||
method: 'POST',
|
||||
headers: {'X-CSRF-TOKEN': CSRF, 'Accept': 'application/json', 'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({ body: 'GIF::' + gifUrl }),
|
||||
});
|
||||
const d = await r.json();
|
||||
appendMsg(d.id, d.body, true, d.created_at, MY_AVA, MY_NAME);
|
||||
if (d.id > lastId) lastId = d.id;
|
||||
scrollBottom(true);
|
||||
} catch(_) {}
|
||||
};
|
||||
|
||||
/* ── Polling ─────────────────────────────── */
|
||||
async function poll() {
|
||||
try {
|
||||
const res = await fetch(`${POLL_URL}?after=${lastId}`, {
|
||||
headers: {'Accept': 'application/json', 'X-CSRF-TOKEN': CSRF}
|
||||
});
|
||||
const d = await res.json();
|
||||
d.messages.forEach(m => {
|
||||
if (m.user_id !== ME_ID) {
|
||||
appendMsg(m.id, m.body, false, m.created_at, m.avatar, m.name);
|
||||
}
|
||||
if (m.id > lastId) lastId = m.id;
|
||||
});
|
||||
} catch(_) {}
|
||||
}
|
||||
|
||||
function startPoll() { polling = setInterval(poll, 3000); }
|
||||
function stopPoll() { clearInterval(polling); polling = null; }
|
||||
document.addEventListener('visibilitychange', () => document.hidden ? stopPoll() : startPoll());
|
||||
startPoll();
|
||||
|
||||
/* ── Emoji picker ────────────────────────── */
|
||||
const EMOJIS = '😀😂😅😊😍🥰😘😎😭😤😡🥺🤔😴🤩🥳😱🙈🙄😏🤗😬😵👍👎❤️🔥💯✨🎉🎊🎮🎬🎵🍕🍜🍣🎃👻🦊🐱🐶🐼🌸🌙⭐🌈💎🚀🏆🎯🔮';
|
||||
|
||||
function initEmoji() {
|
||||
const p = document.getElementById('chat-emoji-picker');
|
||||
if (!p || p.dataset.built) return;
|
||||
p.dataset.built = '1';
|
||||
[...EMOJIS].forEach(em => {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'chat-emoji-btn';
|
||||
btn.textContent = em;
|
||||
btn.addEventListener('click', () => {
|
||||
const pos = inputEl.selectionStart;
|
||||
inputEl.value = inputEl.value.slice(0, pos) + em + inputEl.value.slice(inputEl.selectionEnd);
|
||||
inputEl.selectionStart = inputEl.selectionEnd = pos + em.length;
|
||||
inputEl.dispatchEvent(new Event('input'));
|
||||
inputEl.focus();
|
||||
});
|
||||
p.appendChild(btn);
|
||||
});
|
||||
}
|
||||
|
||||
function toggleEmoji() {
|
||||
emojiOpen = !emojiOpen;
|
||||
if (emojiOpen) { hideGif(); initEmoji(); }
|
||||
document.getElementById('chat-emoji-picker').classList.toggle('show', emojiOpen);
|
||||
document.getElementById('chat-emoji-btn').classList.toggle('active', emojiOpen);
|
||||
}
|
||||
function hideEmoji() {
|
||||
emojiOpen = false;
|
||||
document.getElementById('chat-emoji-picker')?.classList.remove('show');
|
||||
document.getElementById('chat-emoji-btn')?.classList.remove('active');
|
||||
}
|
||||
|
||||
document.getElementById('chat-emoji-btn')?.addEventListener('click', toggleEmoji);
|
||||
|
||||
// Desktop'ta emoji butonu göster
|
||||
if (IS_DESKTOP) {
|
||||
const eb = document.getElementById('chat-emoji-btn');
|
||||
if (eb) eb.style.display = '';
|
||||
}
|
||||
|
||||
/* ── GIF picker ──────────────────────────── */
|
||||
async function searchGifs(q) {
|
||||
const grid = document.getElementById('chat-gif-grid');
|
||||
if (!grid) return;
|
||||
if (!TENOR_KEY) {
|
||||
grid.innerHTML = '<div class="chat-gif-ph">Tenor API key ayarlanmamış.</div>';
|
||||
return;
|
||||
}
|
||||
grid.innerHTML = '<div class="chat-gif-ph">Yükleniyor…</div>';
|
||||
try {
|
||||
const ep = q
|
||||
? `https://tenor.googleapis.com/v2/search?q=${encodeURIComponent(q)}&key=${TENOR_KEY}&limit=12&media_filter=gif`
|
||||
: `https://tenor.googleapis.com/v2/featured?key=${TENOR_KEY}&limit=12&media_filter=gif`;
|
||||
const r = await fetch(ep);
|
||||
const d = await r.json();
|
||||
const results = d.results || [];
|
||||
if (!results.length) { grid.innerHTML = '<div class="chat-gif-ph">Sonuç yok.</div>'; return; }
|
||||
grid.innerHTML = '';
|
||||
results.forEach(g => {
|
||||
const url = g.media_formats?.tinygif?.url || g.media_formats?.gif?.url || '';
|
||||
if (!url) return;
|
||||
const item = document.createElement('div');
|
||||
item.className = 'chat-gif-item';
|
||||
item.innerHTML = `<img src="${escH(url)}" alt="" loading="lazy">`;
|
||||
item.addEventListener('click', () => window.chatSendGif(url));
|
||||
grid.appendChild(item);
|
||||
});
|
||||
} catch(_) { grid.innerHTML = '<div class="chat-gif-ph">Yüklenemedi.</div>'; }
|
||||
}
|
||||
|
||||
function toggleGif() {
|
||||
gifOpen = !gifOpen;
|
||||
if (gifOpen) { hideEmoji(); if (TENOR_KEY) searchGifs(''); setTimeout(() => document.getElementById('chat-gif-input')?.focus(), 80); }
|
||||
document.getElementById('chat-gif-picker').classList.toggle('show', gifOpen);
|
||||
document.getElementById('chat-gif-btn').classList.toggle('active', gifOpen);
|
||||
}
|
||||
function hideGif() {
|
||||
gifOpen = false;
|
||||
document.getElementById('chat-gif-picker')?.classList.remove('show');
|
||||
document.getElementById('chat-gif-btn')?.classList.remove('active');
|
||||
}
|
||||
|
||||
document.getElementById('chat-gif-btn')?.addEventListener('click', toggleGif);
|
||||
document.getElementById('chat-gif-input')?.addEventListener('input', function() {
|
||||
clearTimeout(gifTimer);
|
||||
gifTimer = setTimeout(() => searchGifs(this.value.trim()), 380);
|
||||
});
|
||||
|
||||
/* ── Sesli arama ─────────────────────────── */
|
||||
document.getElementById('call-btn')?.addEventListener('click', async function() {
|
||||
const userId = this.dataset.userId;
|
||||
if (!userId || !window.cpStartCall) { if (window.showToast) showToast('Arama özelliği yüklenemedi.','error'); return; }
|
||||
window.cpConvUserId = userId;
|
||||
window.cpStartCall();
|
||||
});
|
||||
|
||||
/* ── Auto focus ──────────────────────────── */
|
||||
if (IS_DESKTOP) inputEl.focus();
|
||||
|
||||
})();
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,82 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Bildirimler — Animexe')
|
||||
|
||||
@push('styles')
|
||||
<style>
|
||||
.notif-wrap{max-width:700px;margin:0 auto;padding:80px 20px 60px}
|
||||
.notif-hero{margin-bottom:28px}
|
||||
.notif-hero h1{font-size:1.5rem;font-weight:800;color:var(--text);display:flex;align-items:center;gap:10px}
|
||||
.notif-hero p{color:var(--text3);font-size:.88rem;margin-top:4px}
|
||||
|
||||
.notif-card{
|
||||
background:var(--surface);border:1px solid var(--border);border-radius:12px;
|
||||
padding:16px 18px;margin-bottom:10px;display:flex;align-items:flex-start;gap:14px;
|
||||
transition:border-color .15s,background .15s;
|
||||
}
|
||||
.notif-card:hover{border-color:rgba(0,245,255,.25);background:rgba(0,245,255,.02)}
|
||||
.notif-card.unread{border-left:3px solid var(--accent2);background:rgba(0,245,255,.03)}
|
||||
.notif-icon{
|
||||
width:40px;height:40px;border-radius:50%;background:rgba(0,245,255,.1);border:1px solid rgba(0,245,255,.2);
|
||||
display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:1.1rem;color:var(--accent2);
|
||||
}
|
||||
.notif-body{flex:1;min-width:0}
|
||||
.notif-title{font-size:.88rem;font-weight:600;color:var(--text);margin-bottom:3px}
|
||||
.notif-sub{font-size:.78rem;color:var(--text2);line-height:1.5}
|
||||
.notif-time{font-size:.68rem;color:var(--text3);margin-top:5px}
|
||||
.notif-empty{text-align:center;padding:60px 20px;color:var(--text3)}
|
||||
.notif-empty i{font-size:2.5rem;display:block;margin-bottom:12px;opacity:.3}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="notif-wrap">
|
||||
<div class="notif-hero">
|
||||
<h1><i class="bi bi-bell-fill" style="color:var(--accent2)"></i> Bildirimler</h1>
|
||||
<p>Takip ettiğin animelerin yeni bölüm bildirimleri burada görünür.</p>
|
||||
</div>
|
||||
|
||||
@if($notifications->isEmpty())
|
||||
<div class="notif-empty">
|
||||
<i class="bi bi-bell-slash"></i>
|
||||
<div>Henüz bildiriminiz yok.</div>
|
||||
<div style="font-size:.8rem;margin-top:6px">Anime sayfalarından animeleri takip edin, yeni bölüm eklenince bilgilendirilirsiniz.</div>
|
||||
</div>
|
||||
@else
|
||||
@foreach($notifications as $n)
|
||||
@php
|
||||
$d = $n->data;
|
||||
$isEp = $n->type === 'episode';
|
||||
$isAdmin = $n->type === 'admin';
|
||||
$url = $isEp && isset($d['anime_slug'])
|
||||
? route('watch', [$d['anime_slug'], $d['season_number'] ?? 1, $d['episode_number'] ?? 1])
|
||||
: ($isAdmin && !empty($d['url']) ? $d['url'] : '#');
|
||||
@endphp
|
||||
<a href="{{ $url }}" style="text-decoration:none;display:block">
|
||||
<div class="notif-card {{ !$n->is_read ? 'unread' : '' }}">
|
||||
<div class="notif-icon" style="{{ $isAdmin ? 'background:rgba(255,45,125,.1);border-color:rgba(255,45,125,.25);color:var(--accent)' : '' }}">
|
||||
<i class="bi {{ $isAdmin ? ($d['icon'] ?? 'bi-megaphone-fill') : ($isEp ? 'bi-play-circle-fill' : 'bi-bell-fill') }}"></i>
|
||||
</div>
|
||||
<div class="notif-body">
|
||||
@if($isEp)
|
||||
<div class="notif-title">{{ $d['anime_title'] ?? 'Anime' }} — Yeni Bölüm!</div>
|
||||
<div class="notif-sub">
|
||||
Sezon {{ $d['season_number'] ?? 1 }}, {{ $d['episode_number'] ?? 1 }}. Bölüm eklendi
|
||||
@if(!empty($d['episode_title'])) — <em>{{ $d['episode_title'] }}</em>@endif
|
||||
</div>
|
||||
@else
|
||||
<div class="notif-title">{{ $d['title'] ?? 'Bildirim' }}</div>
|
||||
@if(!empty($d['body']))<div class="notif-sub">{{ $d['body'] }}</div>@endif
|
||||
@endif
|
||||
<div class="notif-time">{{ $n->created_at ? \Carbon\Carbon::parse($n->created_at)->diffForHumans() : '' }}</div>
|
||||
</div>
|
||||
@if(!$n->is_read)
|
||||
<div style="width:8px;height:8px;border-radius:50%;background:var(--accent2);flex-shrink:0;margin-top:4px"></div>
|
||||
@endif
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
|
||||
<div class="mt-4">{{ $notifications->links() }}</div>
|
||||
@endif
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,70 @@
|
||||
@if ($paginator->hasPages())
|
||||
<style>
|
||||
.pag{display:flex;align-items:center;justify-content:center;gap:6px;flex-wrap:wrap;padding:8px 0}
|
||||
.pag-btn{
|
||||
display:inline-flex;align-items:center;justify-content:center;
|
||||
min-width:40px;height:40px;padding:0 6px;border-radius:10px;
|
||||
font-size:.85rem;font-weight:600;text-decoration:none;
|
||||
border:1px solid rgba(0,245,255,.12);
|
||||
background:rgba(17,17,31,.85);
|
||||
color:var(--text2,#a0a8c0);
|
||||
transition:background .15s,border-color .15s,color .15s,transform .12s;
|
||||
cursor:pointer;
|
||||
}
|
||||
.pag-btn:hover{
|
||||
background:rgba(0,245,255,.1);
|
||||
border-color:rgba(0,245,255,.35);
|
||||
color:#fff;
|
||||
transform:translateY(-1px);
|
||||
}
|
||||
.pag-btn.active{
|
||||
background:linear-gradient(135deg,var(--accent,#ff2d7d),var(--accent3,#b84dff));
|
||||
border-color:transparent;
|
||||
color:#fff;
|
||||
font-weight:800;
|
||||
box-shadow:0 0 18px rgba(255,45,125,.35);
|
||||
cursor:default;
|
||||
pointer-events:none;
|
||||
}
|
||||
.pag-btn.disabled{
|
||||
opacity:.3;cursor:default;pointer-events:none;
|
||||
}
|
||||
.pag-dots{
|
||||
display:inline-flex;align-items:center;justify-content:center;
|
||||
min-width:40px;height:40px;color:var(--text3,#555);font-size:.9rem;
|
||||
letter-spacing:.1em;
|
||||
}
|
||||
.pag-arrow{font-size:1rem}
|
||||
</style>
|
||||
<nav class="pag" aria-label="Sayfalama">
|
||||
{{-- Önceki --}}
|
||||
@if ($paginator->onFirstPage())
|
||||
<span class="pag-btn disabled pag-arrow">‹</span>
|
||||
@else
|
||||
<a class="pag-btn pag-arrow" href="{{ $paginator->previousPageUrl() }}" rel="prev" aria-label="Önceki sayfa">‹</a>
|
||||
@endif
|
||||
|
||||
{{-- Sayfa numaraları --}}
|
||||
@foreach ($elements as $element)
|
||||
@if (is_string($element))
|
||||
<span class="pag-dots">···</span>
|
||||
@endif
|
||||
@if (is_array($element))
|
||||
@foreach ($element as $page => $url)
|
||||
@if ($page == $paginator->currentPage())
|
||||
<span class="pag-btn active" aria-current="page">{{ $page }}</span>
|
||||
@else
|
||||
<a class="pag-btn" href="{{ $url }}">{{ $page }}</a>
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
@endforeach
|
||||
|
||||
{{-- Sonraki --}}
|
||||
@if ($paginator->hasMorePages())
|
||||
<a class="pag-btn pag-arrow" href="{{ $paginator->nextPageUrl() }}" rel="next" aria-label="Sonraki sayfa">›</a>
|
||||
@else
|
||||
<span class="pag-btn disabled pag-arrow">›</span>
|
||||
@endif
|
||||
</nav>
|
||||
@endif
|
||||
@@ -0,0 +1,49 @@
|
||||
{{-- Sade banner reklam — $ad: App\Models\Ad
|
||||
NOT: class/attribute isimleri bilerek nötr ("ad"/"banner" içermez) —
|
||||
adblocker'lar .ad-banner / [data-ad-id] gibi seçicileri cosmetic filter ile gizliyor.
|
||||
Ayrıca .home-section KULLANMA — o class'ta opacity:0 (scroll reveal) var. --}}
|
||||
@if($ad && $ad->media_url)
|
||||
|
||||
@once
|
||||
<style>
|
||||
.hp-feature-slot{
|
||||
max-width:1400px;
|
||||
margin:0 auto;
|
||||
padding:32px clamp(16px,4vw,48px) 40px;
|
||||
position:relative;
|
||||
}
|
||||
.hp-feature-inner{max-width:970px;margin:0 auto}
|
||||
.hp-feature-label{
|
||||
font-size:10px;letter-spacing:.14em;text-transform:uppercase;
|
||||
color:rgba(255,255,255,.28);margin-bottom:7px;text-align:center;
|
||||
}
|
||||
.hp-feature-media{
|
||||
display:block;border-radius:12px;overflow:hidden;
|
||||
border:1px solid rgba(255,255,255,.06);
|
||||
background:rgba(255,255,255,.02);
|
||||
line-height:0;
|
||||
}
|
||||
.hp-feature-media img{width:100%;display:block;max-height:140px;object-fit:cover}
|
||||
@media(max-width:640px){
|
||||
.hp-feature-slot{padding:24px 16px 28px}
|
||||
.hp-feature-media img{max-height:96px}
|
||||
}
|
||||
</style>
|
||||
@endonce
|
||||
|
||||
<div class="hp-feature-slot">
|
||||
<div class="hp-feature-inner">
|
||||
<div class="hp-feature-label">Sponsorlu</div>
|
||||
@if($ad->click_url)
|
||||
<a href="{{ $ad->click_url }}" target="_blank" rel="noopener sponsored"
|
||||
class="hp-feature-media" data-slot-id="{{ $ad->id }}">
|
||||
<img src="{{ $ad->media_url }}" alt="{{ $ad->name }}" loading="lazy">
|
||||
</a>
|
||||
@else
|
||||
<div class="hp-feature-media" data-slot-id="{{ $ad->id }}">
|
||||
<img src="{{ $ad->media_url }}" alt="{{ $ad->name }}" loading="lazy">
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,129 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Aktivasyon Kodu Gir — Animexe Premium')
|
||||
@push('styles')
|
||||
<style>
|
||||
#pg{background:#06060d;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:80px 20px 60px}
|
||||
.act-card{
|
||||
width:100%;max-width:480px;
|
||||
background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.09);
|
||||
border-radius:24px;padding:44px 40px 40px;position:relative;overflow:hidden;
|
||||
}
|
||||
.act-card::before{
|
||||
content:'';position:absolute;top:-80px;left:50%;transform:translateX(-50%);
|
||||
width:280px;height:200px;border-radius:50%;
|
||||
background:radial-gradient(rgba(0,245,255,.1),transparent 70%);
|
||||
pointer-events:none;
|
||||
}
|
||||
.act-icon{
|
||||
width:64px;height:64px;border-radius:18px;margin:0 auto 20px;
|
||||
background:linear-gradient(135deg,rgba(0,245,255,.15),rgba(184,77,255,.12));
|
||||
border:1px solid rgba(0,245,255,.2);
|
||||
display:flex;align-items:center;justify-content:center;font-size:1.8rem;color:#00f5ff;
|
||||
position:relative;z-index:1;
|
||||
}
|
||||
.act-title{font-size:1.4rem;font-weight:900;color:#fff;text-align:center;margin-bottom:6px;position:relative;z-index:1}
|
||||
.act-sub{font-size:.85rem;color:rgba(255,255,255,.4);text-align:center;margin-bottom:32px;line-height:1.6;position:relative;z-index:1}
|
||||
.act-label{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.1em;color:rgba(255,255,255,.4);margin-bottom:8px}
|
||||
.act-input{
|
||||
width:100%;background:rgba(255,255,255,.06);border:1.5px solid rgba(0,245,255,.2);
|
||||
border-radius:14px;padding:16px 20px;color:#fff;font-size:1.1rem;font-weight:800;
|
||||
letter-spacing:.18em;text-align:center;text-transform:uppercase;outline:none;
|
||||
font-family:inherit;transition:border-color .2s,box-shadow .2s;box-sizing:border-box;
|
||||
}
|
||||
.act-input::placeholder{letter-spacing:.05em;font-weight:400;text-transform:none;font-size:.9rem;color:rgba(255,255,255,.25)}
|
||||
.act-input:focus{border-color:#00f5ff;box-shadow:0 0 0 4px rgba(0,245,255,.1)}
|
||||
.act-input.is-invalid{border-color:#ff2d7d!important;box-shadow:0 0 0 4px rgba(255,45,125,.1)!important}
|
||||
.act-error{
|
||||
display:flex;align-items:center;gap:7px;
|
||||
padding:11px 14px;border-radius:10px;margin-top:10px;
|
||||
background:rgba(255,45,125,.08);border:1px solid rgba(255,45,125,.2);
|
||||
font-size:.82rem;color:#ff2d7d;font-weight:600;
|
||||
}
|
||||
.act-btn{
|
||||
width:100%;padding:15px;border-radius:14px;border:none;cursor:pointer;font-family:inherit;
|
||||
font-size:.95rem;font-weight:800;letter-spacing:.03em;margin-top:18px;
|
||||
background:linear-gradient(135deg,#00f5ff 0%,#0080ff 60%,#b84dff 100%);
|
||||
color:#06060d;box-shadow:0 0 30px rgba(0,245,255,.2),0 6px 20px rgba(0,0,0,.4);
|
||||
transition:transform .15s,box-shadow .15s;
|
||||
}
|
||||
.act-btn:hover{transform:translateY(-2px);box-shadow:0 0 40px rgba(0,245,255,.35),0 8px 28px rgba(0,0,0,.5)}
|
||||
.act-divider{display:flex;align-items:center;gap:12px;margin:22px 0;color:rgba(255,255,255,.18);font-size:.75rem}
|
||||
.act-divider::before,.act-divider::after{content:'';flex:1;height:1px;background:rgba(255,255,255,.08)}
|
||||
.act-back{
|
||||
display:flex;align-items:center;justify-content:center;gap:7px;
|
||||
padding:12px;border-radius:12px;border:1px solid rgba(255,255,255,.1);
|
||||
background:rgba(255,255,255,.04);color:rgba(255,255,255,.5);
|
||||
font-size:.84rem;font-weight:700;text-decoration:none;transition:all .15s;
|
||||
}
|
||||
.act-back:hover{border-color:rgba(255,255,255,.2);color:#fff;background:rgba(255,255,255,.08)}
|
||||
.act-hint{
|
||||
margin-top:20px;padding:12px 16px;border-radius:10px;
|
||||
background:rgba(0,245,255,.04);border:1px solid rgba(0,245,255,.1);
|
||||
font-size:.76rem;color:rgba(255,255,255,.35);line-height:1.55;text-align:center;
|
||||
}
|
||||
.act-hint strong{color:rgba(0,245,255,.7)}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div id="pg">
|
||||
<div class="act-card">
|
||||
<div class="act-icon"><i class="bi bi-key-fill"></i></div>
|
||||
<h1 class="act-title">Aktivasyon Kodu Gir</h1>
|
||||
<p class="act-sub">Satın alma sonrası aldığın kodu girerek Premium üyeliğini hemen aktifleştir.</p>
|
||||
|
||||
@guest
|
||||
<div style="text-align:center;padding:8px 0 16px">
|
||||
<a href="{{ route('frontend.login') }}?next={{ urlencode(route('premium.activate')) }}"
|
||||
style="display:inline-flex;align-items:center;gap:8px;padding:13px 28px;border-radius:12px;background:linear-gradient(135deg,#00f5ff,#b84dff);color:#06060d;font-weight:800;font-size:.9rem;text-decoration:none">
|
||||
<i class="bi bi-box-arrow-in-right"></i> Giriş Yap
|
||||
</a>
|
||||
<div style="margin-top:12px;font-size:.78rem;color:rgba(255,255,255,.3)">
|
||||
Hesabın yoksa <a href="{{ route('frontend.register') }}" style="color:#00f5ff;font-weight:700">kayıt ol</a>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<form method="POST" action="{{ route('premium.activate.redeem') }}">
|
||||
@csrf
|
||||
<div class="act-label">Aktivasyon Kodu</div>
|
||||
<input type="text" name="code" id="act-inp"
|
||||
class="act-input {{ $errors->has('code') ? 'is-invalid' : '' }}"
|
||||
placeholder="XXXX-XXXX-XXXX"
|
||||
value="{{ old('code') }}"
|
||||
maxlength="32" autocomplete="off" autocapitalize="characters" spellcheck="false"
|
||||
autofocus>
|
||||
@if($errors->has('code'))
|
||||
<div class="act-error"><i class="bi bi-exclamation-circle-fill"></i> {{ $errors->first('code') }}</div>
|
||||
@endif
|
||||
<button type="submit" class="act-btn">
|
||||
<i class="bi bi-lightning-charge-fill me-1"></i> Aktifleştir
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="act-hint">
|
||||
Kod formatı: <strong>XXXX-XXXX-XXXX</strong> (büyük harf + tire)<br>
|
||||
Kodu doğru girdiğinden emin ol. Büyük/küçük harf fark etmez.
|
||||
</div>
|
||||
@endguest
|
||||
|
||||
<div class="act-divider">veya</div>
|
||||
<a href="{{ route('premium.plans') }}" class="act-back">
|
||||
<i class="bi bi-arrow-left"></i> Premium Planlarına Dön
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@auth
|
||||
<script>
|
||||
(function(){
|
||||
const inp = document.getElementById('act-inp');
|
||||
if(!inp) return;
|
||||
inp.addEventListener('input', function(){
|
||||
let v = this.value.replace(/[^A-Za-z0-9]/g,'').toUpperCase();
|
||||
const parts = v.match(/.{1,4}/g) || [];
|
||||
this.value = parts.join('-').slice(0, 14);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@endauth
|
||||
@endsection
|
||||
@@ -0,0 +1,662 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Animexe Premium — Anime Deneyimini Zirveye Taşı')
|
||||
@section('meta_description', 'Animexe Premium ile reklamsız izle, özel kozmotikler kazan, erken erişim fırsatlarından yararlan.')
|
||||
@push('styles')
|
||||
<style>
|
||||
:root{--prm-cyan:#00f5ff;--prm-pink:#ff2d7d;--prm-purple:#b84dff;--prm-gold:#ffd60a;--prm-bg:#06060d}
|
||||
|
||||
/* ── Genel ── */
|
||||
#pg{background:var(--prm-bg);min-height:100vh}
|
||||
.prm-wrap{max-width:1160px;margin:0 auto;padding:0 20px 80px}
|
||||
|
||||
/* ── Hero ── */
|
||||
.prm-hero{
|
||||
position:relative;text-align:center;
|
||||
padding:100px 20px 80px;overflow:hidden;
|
||||
}
|
||||
.prm-hero-bg{
|
||||
position:absolute;inset:0;z-index:0;
|
||||
background:radial-gradient(ellipse 80% 60% at 50% 0%,rgba(0,245,255,.09) 0%,transparent 70%),
|
||||
radial-gradient(ellipse 50% 40% at 80% 30%,rgba(184,77,255,.07) 0%,transparent 60%),
|
||||
radial-gradient(ellipse 40% 30% at 20% 60%,rgba(255,45,125,.06) 0%,transparent 60%);
|
||||
}
|
||||
/* Yıldız parçacıkları */
|
||||
.prm-stars{position:absolute;inset:0;z-index:0;pointer-events:none}
|
||||
.prm-stars span{
|
||||
position:absolute;width:2px;height:2px;border-radius:50%;
|
||||
background:#fff;animation:twinkle var(--d,3s) ease-in-out infinite var(--delay,0s);
|
||||
opacity:0;
|
||||
}
|
||||
@keyframes twinkle{0%,100%{opacity:0;transform:scale(1)}50%{opacity:.7;transform:scale(1.4)}}
|
||||
|
||||
.prm-hero-inner{position:relative;z-index:1}
|
||||
.prm-hero-badge{
|
||||
display:inline-flex;align-items:center;gap:7px;
|
||||
padding:6px 16px;border-radius:30px;
|
||||
background:rgba(0,245,255,.08);border:1px solid rgba(0,245,255,.25);
|
||||
font-size:.75rem;font-weight:800;letter-spacing:.1em;text-transform:uppercase;
|
||||
color:var(--prm-cyan);margin-bottom:24px;
|
||||
}
|
||||
.prm-hero-badge i{font-size:.85rem}
|
||||
.prm-hero-title{
|
||||
font-size:clamp(2.2rem,5vw,3.8rem);font-weight:900;line-height:1.15;
|
||||
margin-bottom:16px;letter-spacing:-.02em;
|
||||
}
|
||||
.prm-hero-title .grad{
|
||||
background:linear-gradient(120deg,var(--prm-cyan) 0%,var(--prm-purple) 50%,var(--prm-pink) 100%);
|
||||
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;
|
||||
}
|
||||
.prm-hero-sub{font-size:1.08rem;color:rgba(255,255,255,.5);max-width:560px;margin:0 auto 40px;line-height:1.65}
|
||||
.prm-hero-stats{display:flex;gap:32px;justify-content:center;flex-wrap:wrap;margin-bottom:8px}
|
||||
.prm-stat{display:flex;flex-direction:column;align-items:center;gap:2px}
|
||||
.prm-stat-val{font-size:1.5rem;font-weight:900;color:#fff;line-height:1}
|
||||
.prm-stat-lbl{font-size:.7rem;color:rgba(255,255,255,.35);text-transform:uppercase;letter-spacing:.08em}
|
||||
|
||||
/* ── Aktivasyon başarı banner ── */
|
||||
.prm-success-banner{
|
||||
display:flex;align-items:center;gap:14px;
|
||||
padding:16px 22px;border-radius:14px;margin-bottom:32px;
|
||||
background:rgba(50,220,100,.08);border:1px solid rgba(50,220,100,.3);
|
||||
animation:slideDown .4s ease;
|
||||
}
|
||||
@keyframes slideDown{from{opacity:0;transform:translateY(-12px)}to{opacity:1;transform:none}}
|
||||
.prm-success-banner i{font-size:1.6rem;color:#32dc64;flex-shrink:0}
|
||||
.prm-success-banner strong{color:#32dc64;font-size:.95rem;display:block;margin-bottom:2px}
|
||||
.prm-success-banner span{font-size:.8rem;color:rgba(255,255,255,.5)}
|
||||
|
||||
/* ── Planlar grid ── */
|
||||
.prm-section-lbl{
|
||||
text-align:center;margin-bottom:48px;
|
||||
}
|
||||
.prm-section-lbl h2{font-size:1.6rem;font-weight:800;color:#fff;margin-bottom:8px}
|
||||
.prm-section-lbl p{font-size:.9rem;color:rgba(255,255,255,.4)}
|
||||
|
||||
.prm-plans{
|
||||
display:grid;grid-template-columns:repeat(3,1fr);gap:18px;
|
||||
margin-bottom:72px;
|
||||
}
|
||||
@media(max-width:900px){.prm-plans{grid-template-columns:1fr}}
|
||||
|
||||
.prm-card{
|
||||
position:relative;border-radius:20px;padding:32px 26px 28px;
|
||||
background:rgba(255,255,255,.03);
|
||||
border:1px solid rgba(255,255,255,.08);
|
||||
transition:transform .2s ease,border-color .2s ease,box-shadow .2s ease;
|
||||
display:flex;flex-direction:column;
|
||||
}
|
||||
.prm-card:hover{transform:translateY(-4px);border-color:rgba(255,255,255,.15);box-shadow:0 20px 60px rgba(0,0,0,.4)}
|
||||
.prm-card.featured{
|
||||
background:linear-gradient(145deg,rgba(0,245,255,.06) 0%,rgba(184,77,255,.05) 60%,rgba(255,45,125,.05) 100%);
|
||||
border-color:rgba(0,245,255,.3);
|
||||
box-shadow:0 0 0 1px rgba(0,245,255,.1),0 20px 60px rgba(0,245,255,.08);
|
||||
}
|
||||
.prm-card.featured:hover{box-shadow:0 0 0 1px rgba(0,245,255,.2),0 28px 70px rgba(0,245,255,.14)}
|
||||
|
||||
/* Badge */
|
||||
.prm-card-badge{
|
||||
position:absolute;top:-13px;left:50%;transform:translateX(-50%);
|
||||
padding:4px 18px;border-radius:20px;font-size:.7rem;font-weight:800;
|
||||
letter-spacing:.08em;text-transform:uppercase;white-space:nowrap;
|
||||
background:linear-gradient(90deg,var(--prm-cyan),var(--prm-purple));
|
||||
color:#06060d;box-shadow:0 0 20px rgba(0,245,255,.3);
|
||||
}
|
||||
.prm-card-badge.gold{background:linear-gradient(90deg,#ffd60a,#ff9f0a);box-shadow:0 0 20px rgba(255,214,10,.3)}
|
||||
.prm-card-badge.pink{background:linear-gradient(90deg,var(--prm-pink),var(--prm-purple));box-shadow:0 0 20px rgba(255,45,125,.3)}
|
||||
|
||||
/* Plan içerik */
|
||||
.prm-plan-name{font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.12em;color:rgba(255,255,255,.4);margin-bottom:10px}
|
||||
.prm-plan-price-wrap{margin-bottom:6px;line-height:1}
|
||||
.prm-plan-price{font-size:2.8rem;font-weight:900;color:#fff;letter-spacing:-.04em}
|
||||
.prm-plan-currency{font-size:1.2rem;font-weight:700;color:rgba(255,255,255,.6);vertical-align:top;margin-top:8px;display:inline-block}
|
||||
.prm-plan-period{font-size:.8rem;color:rgba(255,255,255,.35);margin-top:4px}
|
||||
.prm-plan-per-day{font-size:.72rem;color:rgba(255,255,255,.25);margin-bottom:4px}
|
||||
.prm-plan-trial{
|
||||
display:inline-flex;align-items:center;gap:5px;
|
||||
padding:3px 10px;border-radius:10px;
|
||||
background:rgba(255,214,10,.1);border:1px solid rgba(255,214,10,.25);
|
||||
font-size:.7rem;font-weight:700;color:#ffd60a;margin-bottom:18px;
|
||||
}
|
||||
.prm-divider{height:1px;background:rgba(255,255,255,.07);margin:18px 0}
|
||||
|
||||
/* Feature list */
|
||||
.prm-features{list-style:none;padding:0;margin:0 0 24px;display:flex;flex-direction:column;gap:9px;flex:1}
|
||||
.prm-features li{display:flex;align-items:flex-start;gap:9px;font-size:.83rem;color:rgba(255,255,255,.65);line-height:1.4}
|
||||
.prm-features li i.bi-check-circle-fill{color:var(--prm-cyan);font-size:.85rem;flex-shrink:0;margin-top:1px}
|
||||
.prm-features li i.bi-x-circle{color:rgba(255,255,255,.15);font-size:.85rem;flex-shrink:0;margin-top:1px}
|
||||
.prm-features li.dim{color:rgba(255,255,255,.2)}
|
||||
|
||||
/* CTA Buton */
|
||||
.prm-btn-buy{
|
||||
display:flex;align-items:center;justify-content:center;gap:8px;
|
||||
width:100%;padding:13px;border-radius:12px;border:none;
|
||||
font-size:.9rem;font-weight:800;cursor:pointer;font-family:inherit;
|
||||
text-decoration:none;letter-spacing:.02em;
|
||||
transition:transform .15s,box-shadow .15s,opacity .15s;
|
||||
margin-top:auto;
|
||||
}
|
||||
.prm-btn-buy:hover{transform:translateY(-2px)}
|
||||
.prm-btn-buy.primary{
|
||||
background:linear-gradient(135deg,var(--prm-cyan) 0%,#0080ff 60%,var(--prm-purple) 100%);
|
||||
color:#06060d;box-shadow:0 0 30px rgba(0,245,255,.25),0 6px 20px rgba(0,0,0,.4);
|
||||
}
|
||||
.prm-btn-buy.primary:hover{box-shadow:0 0 40px rgba(0,245,255,.4),0 8px 28px rgba(0,0,0,.5)}
|
||||
.prm-btn-buy.outline{
|
||||
background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.12);
|
||||
color:rgba(255,255,255,.75);
|
||||
}
|
||||
.prm-btn-buy.outline:hover{background:rgba(255,255,255,.09);border-color:rgba(255,255,255,.25);color:#fff}
|
||||
.prm-btn-buy.active-plan{
|
||||
background:rgba(50,220,100,.08);border:1px solid rgba(50,220,100,.3);
|
||||
color:#32dc64;cursor:default;
|
||||
}
|
||||
.prm-btn-buy.active-plan:hover{transform:none}
|
||||
.prm-btn-buy.disabled{
|
||||
background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.07);
|
||||
color:rgba(255,255,255,.2);cursor:not-allowed;
|
||||
}
|
||||
.prm-btn-buy.disabled:hover{transform:none}
|
||||
|
||||
/* ── Nasıl Çalışır ── */
|
||||
.prm-how{
|
||||
display:grid;grid-template-columns:repeat(3,1fr);gap:2px;
|
||||
margin-bottom:72px;background:rgba(255,255,255,.04);
|
||||
border:1px solid rgba(255,255,255,.07);border-radius:20px;overflow:hidden;
|
||||
}
|
||||
@media(max-width:700px){.prm-how{grid-template-columns:1fr}}
|
||||
.prm-how-step{
|
||||
padding:32px 28px;position:relative;
|
||||
background:rgba(6,6,13,.6);
|
||||
}
|
||||
.prm-how-step:not(:last-child)::after{
|
||||
content:'';position:absolute;right:0;top:20%;bottom:20%;
|
||||
width:1px;background:rgba(255,255,255,.07);
|
||||
}
|
||||
@media(max-width:700px){.prm-how-step:not(:last-child)::after{display:none}}
|
||||
.prm-how-num{
|
||||
width:40px;height:40px;border-radius:12px;display:flex;align-items:center;justify-content:center;
|
||||
font-size:1.1rem;font-weight:900;margin-bottom:16px;
|
||||
}
|
||||
.prm-how-num.c1{background:rgba(0,245,255,.12);color:var(--prm-cyan)}
|
||||
.prm-how-num.c2{background:rgba(184,77,255,.12);color:var(--prm-purple)}
|
||||
.prm-how-num.c3{background:rgba(50,220,100,.12);color:#32dc64}
|
||||
.prm-how-step h3{font-size:.95rem;font-weight:800;color:#fff;margin-bottom:8px}
|
||||
.prm-how-step p{font-size:.8rem;color:rgba(255,255,255,.4);line-height:1.6;margin:0}
|
||||
|
||||
/* ── Aktivasyon Kutusu ── */
|
||||
.prm-activate-box{
|
||||
border-radius:20px;padding:44px 36px;margin-bottom:72px;
|
||||
background:linear-gradient(135deg,rgba(0,245,255,.04),rgba(184,77,255,.03));
|
||||
border:1px solid rgba(0,245,255,.15);
|
||||
text-align:center;position:relative;overflow:hidden;
|
||||
}
|
||||
.prm-activate-box::before{
|
||||
content:'';position:absolute;top:-60px;left:50%;transform:translateX(-50%);
|
||||
width:300px;height:200px;border-radius:50%;
|
||||
background:radial-gradient(rgba(0,245,255,.08),transparent 70%);
|
||||
pointer-events:none;
|
||||
}
|
||||
.prm-activate-box h2{font-size:1.45rem;font-weight:800;color:#fff;margin-bottom:8px}
|
||||
.prm-activate-box p{font-size:.88rem;color:rgba(255,255,255,.4);margin-bottom:28px;line-height:1.6}
|
||||
.prm-code-form{display:flex;gap:10px;max-width:500px;margin:0 auto;flex-wrap:wrap;justify-content:center}
|
||||
.prm-code-input{
|
||||
flex:1;min-width:220px;
|
||||
background:rgba(255,255,255,.06);border:1px solid rgba(0,245,255,.25);
|
||||
border-radius:12px;padding:14px 18px;color:#fff;font-size:1rem;font-weight:700;
|
||||
letter-spacing:.12em;text-align:center;text-transform:uppercase;outline:none;
|
||||
font-family:inherit;transition:border-color .2s,box-shadow .2s;
|
||||
}
|
||||
.prm-code-input::placeholder{letter-spacing:.05em;font-weight:400;text-transform:none;font-size:.88rem;color:rgba(255,255,255,.3)}
|
||||
.prm-code-input:focus{border-color:var(--prm-cyan);box-shadow:0 0 0 3px rgba(0,245,255,.12)}
|
||||
.prm-code-input.is-invalid{border-color:var(--prm-pink)!important;box-shadow:0 0 0 3px rgba(255,45,125,.1)!important}
|
||||
.prm-code-btn{
|
||||
padding:14px 28px;border-radius:12px;border:none;cursor:pointer;font-family:inherit;
|
||||
font-size:.9rem;font-weight:800;letter-spacing:.03em;
|
||||
background:linear-gradient(135deg,var(--prm-cyan),var(--prm-purple));
|
||||
color:#06060d;box-shadow:0 0 24px rgba(0,245,255,.2);
|
||||
transition:transform .15s,box-shadow .15s;
|
||||
}
|
||||
.prm-code-btn:hover{transform:translateY(-2px);box-shadow:0 0 36px rgba(0,245,255,.35)}
|
||||
.prm-code-error{
|
||||
width:100%;text-align:center;font-size:.8rem;color:var(--prm-pink);
|
||||
margin-top:8px;font-weight:600;
|
||||
}
|
||||
.prm-activate-login-note{
|
||||
margin-top:14px;font-size:.78rem;color:rgba(255,255,255,.3);
|
||||
}
|
||||
.prm-activate-login-note a{color:var(--prm-cyan);text-decoration:none;font-weight:700}
|
||||
.prm-activate-login-note a:hover{text-decoration:underline}
|
||||
|
||||
/* ── Özellik Showcase ── */
|
||||
.prm-features-grid{
|
||||
display:grid;grid-template-columns:repeat(2,1fr);gap:32px;margin-bottom:72px;
|
||||
}
|
||||
@media(max-width:700px){.prm-features-grid{grid-template-columns:1fr}}
|
||||
.prm-feat-cat{
|
||||
background:rgba(255,255,255,.025);border:1px solid rgba(255,255,255,.07);
|
||||
border-radius:16px;padding:24px;
|
||||
}
|
||||
.prm-feat-cat-hdr{
|
||||
display:flex;align-items:center;gap:10px;margin-bottom:18px;padding-bottom:14px;
|
||||
border-bottom:1px solid rgba(255,255,255,.06);
|
||||
}
|
||||
.prm-feat-cat-icon{
|
||||
width:36px;height:36px;border-radius:10px;display:flex;align-items:center;justify-content:center;
|
||||
font-size:1rem;flex-shrink:0;
|
||||
}
|
||||
.prm-feat-cat-hdr h3{font-size:.9rem;font-weight:800;color:#fff;margin:0}
|
||||
.prm-feat-list{display:flex;flex-direction:column;gap:10px}
|
||||
.prm-feat-item{display:flex;align-items:flex-start;gap:10px}
|
||||
.prm-feat-item-icon{
|
||||
width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;
|
||||
font-size:.75rem;flex-shrink:0;margin-top:1px;
|
||||
}
|
||||
.prm-feat-item-body{flex:1;min-width:0}
|
||||
.prm-feat-item-name{font-size:.82rem;font-weight:700;color:rgba(255,255,255,.8);margin-bottom:2px}
|
||||
.prm-feat-item-desc{font-size:.72rem;color:rgba(255,255,255,.35);line-height:1.45}
|
||||
|
||||
/* Kozmetik Preview */
|
||||
.prm-cosmetics{
|
||||
margin-bottom:72px;text-align:center;
|
||||
}
|
||||
.prm-cosmetics-title{font-size:1.35rem;font-weight:800;color:#fff;margin-bottom:8px}
|
||||
.prm-cosmetics-sub{font-size:.85rem;color:rgba(255,255,255,.35);margin-bottom:36px}
|
||||
.prm-cosmetics-grid{display:flex;flex-wrap:wrap;gap:12px;justify-content:center;margin-bottom:28px}
|
||||
|
||||
/* Username color chips */
|
||||
.uc-chip{
|
||||
padding:5px 16px;border-radius:20px;font-size:.82rem;font-weight:700;
|
||||
background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1);
|
||||
cursor:default;white-space:nowrap;
|
||||
}
|
||||
|
||||
/* Frame badges */
|
||||
.frame-badge{
|
||||
width:52px;height:52px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;
|
||||
font-size:1.2rem;font-weight:800;color:#fff;position:relative;
|
||||
}
|
||||
.frame-badge::before{
|
||||
content:'';position:absolute;inset:-3px;border-radius:50%;
|
||||
animation:frame-spin 3s linear infinite;
|
||||
}
|
||||
@keyframes frame-spin{to{transform:rotate(360deg)}}
|
||||
.frame-badge.fr-neon::before{background:conic-gradient(#00f5ff,#b84dff,#00f5ff)}
|
||||
.frame-badge.fr-fire::before{background:conic-gradient(#ff6b35,#ff2d7d,#ff8c00,#ff6b35)}
|
||||
.frame-badge.fr-galaxy::before{background:conic-gradient(#7c3aed,#b84dff,#4a1d96,#7c3aed)}
|
||||
.frame-badge.fr-gold::before{background:conic-gradient(#ffd700,#ff8c00,#ffd700)}
|
||||
.frame-badge.fr-sakura::before{background:conic-gradient(#ff9ec4,#ff2d7d,#ffd6e7,#ff9ec4)}
|
||||
.frame-badge.fr-rainbow::before{background:conic-gradient(#f00,#ff8c00,#ffd700,#0c0,#08f,#8b00ff,#f08,#f00)}
|
||||
.frame-badge.fr-ice::before{background:conic-gradient(#a8edff,#60cfff,#a8edff)}
|
||||
.frame-badge-inner{position:relative;z-index:1;width:44px;height:44px;border-radius:50%;background:#111;display:flex;align-items:center;justify-content:center;font-size:.65rem;text-align:center;padding:2px;color:rgba(255,255,255,.7)}
|
||||
|
||||
/* Comment bg preview */
|
||||
.cb-preview{
|
||||
padding:10px 16px;border-radius:10px;font-size:.8rem;color:#fff;font-weight:600;
|
||||
white-space:nowrap;position:relative;overflow:hidden;
|
||||
}
|
||||
.cb-preview::before{content:'';position:absolute;inset:0;opacity:.7}
|
||||
.cb-fire::before{background:linear-gradient(135deg,#ff6b35,#ff2d7d)}
|
||||
.cb-aurora::before{background:linear-gradient(135deg,#00c8d4,#b84dff)}
|
||||
.cb-stars::before{background:linear-gradient(135deg,#1a1a3a,#4a1d96)}
|
||||
.cb-sakura::before{background:linear-gradient(135deg,#ff9ec4,#ff2d7d)}
|
||||
.cb-neon::before{background:linear-gradient(135deg,#00f5ff,#0040ff)}
|
||||
.cb-galaxy::before{background:linear-gradient(135deg,#0a0020,#7c3aed)}
|
||||
.cb-ice::before{background:linear-gradient(135deg,#a8edff,#006fbf)}
|
||||
.cb-preview span{position:relative;z-index:1}
|
||||
|
||||
/* ── FAQ ── */
|
||||
.prm-faq{margin-bottom:48px}
|
||||
.prm-faq h2{font-size:1.35rem;font-weight:800;color:#fff;margin-bottom:28px;text-align:center}
|
||||
.prm-faq-item{
|
||||
border-bottom:1px solid rgba(255,255,255,.06);overflow:hidden;
|
||||
}
|
||||
.prm-faq-q{
|
||||
display:flex;align-items:center;justify-content:space-between;
|
||||
padding:16px 4px;cursor:pointer;font-size:.9rem;font-weight:700;color:rgba(255,255,255,.75);
|
||||
transition:color .15s;user-select:none;
|
||||
background:none;border:none;width:100%;text-align:left;font-family:inherit;
|
||||
gap:12px;
|
||||
}
|
||||
.prm-faq-q:hover{color:#fff}
|
||||
.prm-faq-q i{flex-shrink:0;transition:transform .25s ease;color:rgba(255,255,255,.3)}
|
||||
.prm-faq-item.open .prm-faq-q i{transform:rotate(45deg);color:var(--prm-cyan)}
|
||||
.prm-faq-a{
|
||||
max-height:0;overflow:hidden;
|
||||
transition:max-height .3s ease,padding .3s ease;
|
||||
font-size:.84rem;color:rgba(255,255,255,.45);line-height:1.7;padding:0 4px;
|
||||
}
|
||||
.prm-faq-item.open .prm-faq-a{max-height:200px;padding-bottom:16px}
|
||||
|
||||
/* ── Mevcut Plan Banner ── */
|
||||
.prm-active-banner{
|
||||
display:flex;align-items:center;gap:16px;padding:18px 24px;border-radius:14px;
|
||||
background:rgba(0,245,255,.06);border:1px solid rgba(0,245,255,.2);margin-bottom:36px;
|
||||
flex-wrap:wrap;
|
||||
}
|
||||
.prm-active-banner i{font-size:1.8rem;color:var(--prm-cyan);flex-shrink:0}
|
||||
.prm-active-banner-body{flex:1;min-width:0}
|
||||
.prm-active-banner-title{font-size:.95rem;font-weight:800;color:#fff;margin-bottom:2px}
|
||||
.prm-active-banner-sub{font-size:.78rem;color:rgba(255,255,255,.4)}
|
||||
.prm-active-banner-action{flex-shrink:0}
|
||||
.prm-active-banner-action a{
|
||||
padding:9px 20px;border-radius:10px;border:1px solid rgba(0,245,255,.3);
|
||||
background:rgba(0,245,255,.07);color:var(--prm-cyan);font-size:.8rem;font-weight:700;
|
||||
text-decoration:none;transition:all .15s;white-space:nowrap;display:inline-block;
|
||||
}
|
||||
.prm-active-banner-action a:hover{background:rgba(0,245,255,.14);border-color:var(--prm-cyan)}
|
||||
|
||||
@media(max-width:600px){
|
||||
.prm-hero{padding:72px 16px 56px}
|
||||
.prm-activate-box{padding:32px 20px}
|
||||
.prm-how-step{padding:24px 20px}
|
||||
.prm-card{padding:26px 20px 22px}
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div id="pg">
|
||||
<div class="prm-hero">
|
||||
<div class="prm-hero-bg"></div>
|
||||
<div class="prm-stars" id="prm-stars"></div>
|
||||
<div class="prm-hero-inner">
|
||||
<div class="prm-hero-badge"><i class="bi bi-stars"></i> Animexe Premium</div>
|
||||
<h1 class="prm-hero-title">
|
||||
Anime deneyimini<br><span class="grad">zirveye taşı</span>
|
||||
</h1>
|
||||
<p class="prm-hero-sub">
|
||||
Reklamsız izleme, özel profil kozmetikleri, erken bölüm erişimi ve daha fazlası — hepsi tek bir Premium üyelikte.
|
||||
</p>
|
||||
<div class="prm-hero-stats">
|
||||
<div class="prm-stat"><span class="prm-stat-val">∞</span><span class="prm-stat-lbl">İçerik</span></div>
|
||||
<div class="prm-stat"><span class="prm-stat-val">{{ count($featureGroups ?? []) > 0 ? array_sum(array_map(fn($g) => count($g['perks']), $featureGroups)) : '20+' }}</span><span class="prm-stat-lbl">Özel Özellik</span></div>
|
||||
<div class="prm-stat"><span class="prm-stat-val">7/24</span><span class="prm-stat-lbl">Destek</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="prm-wrap">
|
||||
|
||||
{{-- Aktivasyon başarı mesajı --}}
|
||||
@if(session('activation_success'))
|
||||
<div class="prm-success-banner">
|
||||
<i class="bi bi-patch-check-fill"></i>
|
||||
<div>
|
||||
<strong>Premium aktif! 🎉 {{ session('activation_success.plan') }} planına hoş geldin.</strong>
|
||||
<span>Üyeliğin {{ session('activation_success.expires_at') }} tarihine kadar geçerli.</span>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Mevcut premium kullanıcı banner --}}
|
||||
@auth
|
||||
@if(auth()->user()->isPremium())
|
||||
<div class="prm-active-banner">
|
||||
<i class="bi bi-shield-fill-check"></i>
|
||||
<div class="prm-active-banner-body">
|
||||
<div class="prm-active-banner-title">Premium üyeliğin aktif 🎉</div>
|
||||
<div class="prm-active-banner-sub">
|
||||
Bitiş tarihi: {{ auth()->user()->premium_expires_at?->format('d MMMM Y') ?? auth()->user()->premium_expires_at?->format('d.m.Y') }}
|
||||
· Süre uzatmak için aşağıdan yeni bir plan satın alabilirsin.
|
||||
</div>
|
||||
</div>
|
||||
<div class="prm-active-banner-action">
|
||||
<a href="{{ route('profile') }}"><i class="bi bi-person-circle me-1"></i>Profili Gör</a>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endauth
|
||||
|
||||
{{-- Planlar --}}
|
||||
@if(count($plans ?? []) > 0)
|
||||
<div class="prm-section-lbl">
|
||||
<h2>Planını Seç</h2>
|
||||
<p>Tüm planlar aynı özellikleri içerir — süre ne kadar uzunsa o kadar tasarruf edersin.</p>
|
||||
</div>
|
||||
<div class="prm-plans">
|
||||
@foreach($plans as $idx => $plan)
|
||||
@php
|
||||
$isFeatured = $plan->badge_label && $idx == 1 || ($plan->badge_label && str_contains(strtolower($plan->badge_label), 'popül'));
|
||||
$isActive = auth()->check() && auth()->user()->subscriptions()->where('plan_id', $plan->id)->where('status','active')->exists();
|
||||
$perDay = $plan->duration_days > 0 ? round($plan->price / $plan->duration_days, 2) : 0;
|
||||
$accentCls = $isFeatured ? 'featured' : '';
|
||||
@endphp
|
||||
<div class="prm-card {{ $accentCls }}">
|
||||
@if($plan->badge_label)
|
||||
@php
|
||||
$badgeCls = match(true) {
|
||||
str_contains(strtolower($plan->badge_label), 'değer') => 'gold',
|
||||
str_contains(strtolower($plan->badge_label), 'popül') => '',
|
||||
default => 'pink',
|
||||
};
|
||||
@endphp
|
||||
<div class="prm-card-badge {{ $badgeCls }}">{{ $plan->badge_label }}</div>
|
||||
@endif
|
||||
|
||||
<div class="prm-plan-name">{{ $plan->name }}</div>
|
||||
<div class="prm-plan-price-wrap">
|
||||
<span class="prm-plan-currency">₺</span><span class="prm-plan-price">{{ number_format($plan->price, 0, ',', '.') }}</span>
|
||||
</div>
|
||||
<div class="prm-plan-period">
|
||||
@if($plan->duration_days >= 365)
|
||||
{{ intdiv($plan->duration_days, 365) }} yıl
|
||||
@elseif($plan->duration_days >= 30)
|
||||
{{ intdiv($plan->duration_days, 30) }} ay
|
||||
@else
|
||||
{{ $plan->duration_days }} gün
|
||||
@endif
|
||||
· Günde ≈ ₺{{ $perDay }}
|
||||
</div>
|
||||
|
||||
@if($plan->trial_days)
|
||||
<div class="prm-plan-trial"><i class="bi bi-gift-fill"></i> İlk {{ $plan->trial_days }} gün ücretsiz!</div>
|
||||
@endif
|
||||
|
||||
<div class="prm-divider"></div>
|
||||
|
||||
@if(count($plan->features ?? []) > 0)
|
||||
<ul class="prm-features">
|
||||
@foreach($plan->features as $feat)
|
||||
<li><i class="bi bi-check-circle-fill"></i> {{ $feat }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
|
||||
@if($isActive)
|
||||
<a class="prm-btn-buy active-plan"><i class="bi bi-check-circle-fill"></i> Mevcut Planın</a>
|
||||
@elseif($plan->purchase_link)
|
||||
<a href="{{ $plan->purchase_link }}" target="_blank" rel="noopener" class="prm-btn-buy {{ $isFeatured ? 'primary' : 'outline' }}">
|
||||
<i class="bi bi-bag-fill"></i> Satın Al
|
||||
</a>
|
||||
@else
|
||||
<span class="prm-btn-buy disabled"><i class="bi bi-clock"></i> Yakında</span>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Nasıl Çalışır --}}
|
||||
<div class="prm-section-lbl">
|
||||
<h2>Nasıl Çalışır?</h2>
|
||||
<p>Üç adımda premium üyeliğini aktifleştir.</p>
|
||||
</div>
|
||||
<div class="prm-how">
|
||||
<div class="prm-how-step">
|
||||
<div class="prm-how-num c1"><i class="bi bi-1-circle-fill"></i></div>
|
||||
<h3>Paket Seç & Öde</h3>
|
||||
<p>Yukarıdaki planlardan birini seç, "Satın Al" butonuna tıkla ve güvenli ödeme sayfasına yönlendir. Ödemeyi tamamla.</p>
|
||||
</div>
|
||||
<div class="prm-how-step">
|
||||
<div class="prm-how-num c2"><i class="bi bi-2-circle-fill"></i></div>
|
||||
<h3>Aktivasyon Kodunu Al</h3>
|
||||
<p>Ödemen onaylandıktan sonra sana özel bir aktivasyon kodu gönderilir. Bu kodu saklaman yeterli.</p>
|
||||
</div>
|
||||
<div class="prm-how-step">
|
||||
<div class="prm-how-num c3"><i class="bi bi-3-circle-fill"></i></div>
|
||||
<h3>Kodu Gir, Keyfini Çıkar</h3>
|
||||
<p>Aşağıdaki kutuya aktivasyon kodunu gir. Anında aktif olur, tüm premium ayrıcalıklar hesabına yüklenir!</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Aktivasyon Kutusu --}}
|
||||
<div class="prm-activate-box" id="activate">
|
||||
<h2>Aktivasyon Kodun Var mı?</h2>
|
||||
<p>Satın alma sonrası aldığın kodu girerek Premium üyeliğini hemen aktifleştir.</p>
|
||||
|
||||
@auth
|
||||
<form method="POST" action="{{ route('premium.activate.redeem') }}" class="prm-code-form">
|
||||
@csrf
|
||||
<input type="text" name="code" id="prm-code-inp" class="prm-code-input {{ $errors->has('code') ? 'is-invalid' : '' }}"
|
||||
placeholder="XXXX-XXXX-XXXX" maxlength="32" autocomplete="off" autocapitalize="characters"
|
||||
value="{{ old('code') }}" spellcheck="false">
|
||||
<button type="submit" class="prm-code-btn"><i class="bi bi-lightning-fill me-1"></i>Aktifleştir</button>
|
||||
@if($errors->has('code'))
|
||||
<div class="prm-code-error"><i class="bi bi-exclamation-circle me-1"></i>{{ $errors->first('code') }}</div>
|
||||
@endif
|
||||
</form>
|
||||
@else
|
||||
<form class="prm-code-form">
|
||||
<input type="text" class="prm-code-input" placeholder="XXXX-XXXX-XXXX" disabled>
|
||||
<button type="button" onclick="window.location.href='{{ route('frontend.register') }}?next={{ urlencode(route('premium.activate')) }}'" class="prm-code-btn">
|
||||
<i class="bi bi-person-plus-fill me-1"></i>Giriş Yap & Aktifleştir
|
||||
</button>
|
||||
</form>
|
||||
<div class="prm-activate-login-note">
|
||||
Aktivasyon kodu kullanmak için <a href="{{ route('frontend.register') }}">üye olman</a> veya <a href="{{ route('frontend.login') }}">giriş yapman</a> gerekiyor.
|
||||
</div>
|
||||
@endauth
|
||||
</div>
|
||||
|
||||
{{-- Özellikler Showcase --}}
|
||||
@if(count($featureGroups ?? []) > 0)
|
||||
<div class="prm-section-lbl">
|
||||
<h2>Premium Ayrıcalıklar</h2>
|
||||
<p>Premium üyeliğinle birlikte gelen tüm özellikler.</p>
|
||||
</div>
|
||||
<div class="prm-features-grid">
|
||||
@foreach($featureGroups as $group)
|
||||
@php
|
||||
$colors = [
|
||||
'Profil' => ['bg'=>'rgba(184,77,255,.12)','color'=>'#b84dff','icon'=>'bi-person-circle'],
|
||||
'İzleme' => ['bg'=>'rgba(0,245,255,.12)','color'=>'#00f5ff','icon'=>'bi-play-circle-fill'],
|
||||
'Sosyal' => ['bg'=>'rgba(255,45,125,.12)','color'=>'#ff2d7d','icon'=>'bi-chat-heart-fill'],
|
||||
'Hesap' => ['bg'=>'rgba(255,214,10,.12)','color'=>'#ffd60a','icon'=>'bi-shield-fill-check'],
|
||||
];
|
||||
$c = $colors[$group['label']] ?? ['bg'=>'rgba(255,255,255,.08)','color'=>'#fff','icon'=>'bi-star-fill'];
|
||||
@endphp
|
||||
<div class="prm-feat-cat">
|
||||
<div class="prm-feat-cat-hdr">
|
||||
<div class="prm-feat-cat-icon" style="background:{{ $c['bg'] }};color:{{ $c['color'] }}">
|
||||
<i class="bi {{ $c['icon'] }}"></i>
|
||||
</div>
|
||||
<h3>{{ $group['label'] }}</h3>
|
||||
</div>
|
||||
<div class="prm-feat-list">
|
||||
@foreach(array_slice($group['perks'], 0, 6) as $perk)
|
||||
<div class="prm-feat-item">
|
||||
<div class="prm-feat-item-icon" style="background:{{ $c['bg'] }};color:{{ $c['color'] }}">
|
||||
<i class="bi {{ $perk['icon'] ?? 'bi-check' }}"></i>
|
||||
</div>
|
||||
<div class="prm-feat-item-body">
|
||||
<div class="prm-feat-item-name">{{ $perk['name'] }}</div>
|
||||
@if(!empty($perk['desc']))<div class="prm-feat-item-desc">{{ $perk['desc'] }}</div>@endif
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Kozmetik Preview --}}
|
||||
<div class="prm-cosmetics">
|
||||
<div class="prm-cosmetics-title">Profilini Kişiselleştir</div>
|
||||
<div class="prm-cosmetics-sub">Premium üyeler için özel görsel özelleştirmeler</div>
|
||||
|
||||
<div style="display:flex;flex-wrap:wrap;gap:32px;justify-content:center;margin-bottom:36px">
|
||||
<div style="text-align:center">
|
||||
<div style="font-size:.7rem;text-transform:uppercase;letter-spacing:.1em;color:rgba(255,255,255,.3);margin-bottom:14px">Profil Çerçeveleri</div>
|
||||
<div style="display:flex;gap:14px;flex-wrap:wrap;justify-content:center">
|
||||
@foreach(['neon','fire','galaxy','gold','sakura','rainbow','ice'] as $fr)
|
||||
<div class="frame-badge fr-{{ $fr }}">
|
||||
<div class="frame-badge-inner">{{ Str::upper(substr($fr,0,2)) }}</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align:center">
|
||||
<div style="font-size:.7rem;text-transform:uppercase;letter-spacing:.1em;color:rgba(255,255,255,.3);margin-bottom:14px">Yorum Arka Planları</div>
|
||||
<div style="display:flex;gap:8px;flex-wrap:wrap;justify-content:center">
|
||||
@foreach(['fire'=>'Ateş','aurora'=>'Aurora','stars'=>'Yıldız','sakura'=>'Sakura','neon'=>'Neon','galaxy'=>'Galaksi','ice'=>'Buz'] as $bg => $lbl)
|
||||
<div class="cb-preview cb-{{ $bg }}"><span>{{ $lbl }}</span></div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align:center">
|
||||
<div style="font-size:.7rem;text-transform:uppercase;letter-spacing:.1em;color:rgba(255,255,255,.3);margin-bottom:14px">Kullanıcı Adı Renkleri</div>
|
||||
<div style="display:flex;gap:8px;flex-wrap:wrap;justify-content:center">
|
||||
@foreach([
|
||||
['gradient'=>'linear-gradient(90deg,#00f5ff,#0080ff)','name'=>'Okyanus'],
|
||||
['gradient'=>'linear-gradient(90deg,#ff2d7d,#b84dff)','name'=>'Galaksi'],
|
||||
['gradient'=>'linear-gradient(90deg,#ffd700,#ff8c00)','name'=>'Altın'],
|
||||
['gradient'=>'linear-gradient(90deg,#32dc64,#00c8d4)','name'=>'Orman'],
|
||||
['gradient'=>'linear-gradient(90deg,#ff6b35,#ff2d7d)','name'=>'Ateş'],
|
||||
['gradient'=>'linear-gradient(90deg,#a8edff,#006fbf)','name'=>'Buz'],
|
||||
['gradient'=>'linear-gradient(90deg,#b84dff,#7c3aed)','name'=>'Mor'],
|
||||
] as $uc)
|
||||
<span class="uc-chip" style="background:{{ $uc['gradient'] }};-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;border-color:rgba(255,255,255,.12)">{{ $uc['name'] }}</span>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- FAQ --}}
|
||||
<div class="prm-faq">
|
||||
<h2>Sık Sorulan Sorular</h2>
|
||||
@foreach([
|
||||
['s'=>'Ödeme yaptıktan sonra nasıl aktifleştiririm?','c'=>'Ödemen onaylandıktan sonra sana aktivasyon kodu gönderilir. Bu sayfadaki "Aktivasyon Kodun Var mı?" kısmına kodu girip "Aktifleştir" butonuna tıklaman yeterli.'],
|
||||
['s'=>'Mevcut Premium üyeliğim varken başka bir kod girebilir miyim?','c'=>'Evet! Mevcut üyelik süren bitmeden kod girersen süreler üst üste eklenir (stack). Hiç süre kaybetmezsin.'],
|
||||
['s'=>'Aktivasyon kodum çalışmıyorsa ne yapmalıyım?','c'=>'Kodu büyük harflerle ve tire işaretleriyle birlikte girdiğinden emin ol (XXXX-XXXX-XXXX). Sorun devam ederse destek hattına başvur.'],
|
||||
['s'=>'Premium üyeliğimi iptal edebilir miyim?','c'=>'Premium üyeliğin süre tabanlıdır; otomatik yenileme yoktur. Süre dolunca normal hesabına dönersin.'],
|
||||
['s'=>'Premium özellikler hangi cihazlarda çalışır?','c'=>'Tüm cihazlarda (bilgisayar, tablet, telefon) çalışır. Hesabına giriş yaptığın her yerde premium ayrıcalıklarını kullanabilirsin.'],
|
||||
] as $faq)
|
||||
<div class="prm-faq-item">
|
||||
<button class="prm-faq-q" onclick="this.closest('.prm-faq-item').classList.toggle('open')">
|
||||
<span>{{ $faq['s'] }}</span>
|
||||
<i class="bi bi-plus-lg"></i>
|
||||
</button>
|
||||
<div class="prm-faq-a">{{ $faq['c'] }}</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
</div>{{-- /prm-wrap --}}
|
||||
</div>{{-- /pg --}}
|
||||
|
||||
<script>
|
||||
// Yıldız parçacıkları
|
||||
(function(){
|
||||
const c = document.getElementById('prm-stars');
|
||||
if(!c) return;
|
||||
for(let i=0;i<60;i++){
|
||||
const s = document.createElement('span');
|
||||
s.style.cssText = `left:${Math.random()*100}%;top:${Math.random()*100}%;--d:${2+Math.random()*4}s;--delay:-${Math.random()*4}s`;
|
||||
c.appendChild(s);
|
||||
}
|
||||
})();
|
||||
|
||||
// Kod input: otomatik büyük harf + tire formatı
|
||||
(function(){
|
||||
const inp = document.getElementById('prm-code-inp');
|
||||
if(!inp) return;
|
||||
inp.addEventListener('input', function(){
|
||||
let v = this.value.replace(/[^A-Za-z0-9]/g,'').toUpperCase();
|
||||
const parts = v.match(/.{1,4}/g) || [];
|
||||
this.value = parts.join('-').slice(0, 14);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@endsection
|
||||
@@ -0,0 +1,904 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Profil Ayarları — Animexe')
|
||||
|
||||
@push('styles')
|
||||
<style>
|
||||
.ps-wrap {
|
||||
max-width: 860px;
|
||||
margin: 0 auto;
|
||||
padding: 40px 20px 80px;
|
||||
}
|
||||
|
||||
/* Banner + Avatar */
|
||||
.ps-banner-area {
|
||||
position: relative;
|
||||
height: 200px;
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(135deg, #0d0d1a, #1a0a2e);
|
||||
margin-bottom: 0;
|
||||
cursor: pointer;
|
||||
transition: filter .2s;
|
||||
}
|
||||
.ps-banner-area:hover { filter: brightness(0.85); }
|
||||
.ps-banner-img {
|
||||
width: 100%; height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
.ps-banner-overlay {
|
||||
position: absolute; inset: 0;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
background: rgba(0,0,0,.45);
|
||||
opacity: 0;
|
||||
transition: opacity .2s;
|
||||
flex-direction: column; gap: 8px;
|
||||
font-size: .85rem; color: #fff;
|
||||
}
|
||||
.ps-banner-area:hover .ps-banner-overlay { opacity: 1; }
|
||||
.ps-banner-area::after {
|
||||
content: '';
|
||||
position: absolute; inset: 0;
|
||||
background: linear-gradient(to bottom, transparent 60%, rgba(0,0,0,.7));
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.ps-avatar-row {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 20px;
|
||||
margin-top: -48px;
|
||||
padding: 0 24px;
|
||||
margin-bottom: 24px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
.ps-avatar-wrap {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ps-avatar {
|
||||
width: 96px; height: 96px;
|
||||
border-radius: 20px;
|
||||
border: 3px solid var(--ps-color, #00f5ff);
|
||||
object-fit: cover;
|
||||
background: #1a1a2e;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 2.2rem; font-weight: 900; color: #fff;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 8px 32px rgba(0,0,0,.5);
|
||||
transition: border-color .3s;
|
||||
}
|
||||
.ps-avatar img { width: 100%; height: 100%; object-fit: cover; }
|
||||
.ps-avatar-overlay {
|
||||
position: absolute; inset: 0;
|
||||
border-radius: 18px;
|
||||
background: rgba(0,0,0,.55);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
opacity: 0;
|
||||
transition: opacity .2s;
|
||||
font-size: 1.2rem; color: #fff;
|
||||
}
|
||||
.ps-avatar-wrap:hover .ps-avatar-overlay { opacity: 1; }
|
||||
.ps-avatar-name {
|
||||
padding-bottom: 8px;
|
||||
font-size: 1.3rem;
|
||||
font-weight: 800;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Cards */
|
||||
.ps-card {
|
||||
background: rgba(255,255,255,.04);
|
||||
border: 1px solid rgba(255,255,255,.08);
|
||||
border-radius: 16px;
|
||||
padding: 24px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.ps-card-title {
|
||||
font-size: .8rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .08em;
|
||||
color: rgba(255,255,255,.4);
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid rgba(255,255,255,.06);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.ps-card-title i { font-size: 1rem; }
|
||||
|
||||
/* Form elements */
|
||||
.ps-label {
|
||||
display: block;
|
||||
font-size: .8rem;
|
||||
color: rgba(255,255,255,.5);
|
||||
margin-bottom: 6px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.ps-input {
|
||||
width: 100%;
|
||||
background: rgba(255,255,255,.06);
|
||||
border: 1px solid rgba(255,255,255,.1);
|
||||
border-radius: 10px;
|
||||
padding: 10px 14px;
|
||||
color: #fff;
|
||||
font-size: .9rem;
|
||||
transition: border-color .2s, background .2s;
|
||||
outline: none;
|
||||
}
|
||||
.ps-input:focus {
|
||||
border-color: var(--ps-color, #00f5ff);
|
||||
background: rgba(255,255,255,.09);
|
||||
}
|
||||
.ps-input::placeholder { color: rgba(255,255,255,.25); }
|
||||
.ps-input.with-prefix { padding-left: 36px; }
|
||||
|
||||
.ps-field { margin-bottom: 16px; position: relative; }
|
||||
.ps-prefix {
|
||||
position: absolute;
|
||||
left: 12px; top: 50%; transform: translateY(-50%);
|
||||
color: rgba(255,255,255,.35);
|
||||
font-size: .9rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.ps-textarea {
|
||||
resize: vertical;
|
||||
min-height: 80px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Color picker */
|
||||
.ps-color-grid {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
.ps-color-swatch {
|
||||
width: 32px; height: 32px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
border: 2px solid transparent;
|
||||
transition: transform .15s, border-color .15s;
|
||||
position: relative;
|
||||
}
|
||||
.ps-color-swatch:hover { transform: scale(1.15); }
|
||||
.ps-color-swatch.active { border-color: #fff; transform: scale(1.1); }
|
||||
.ps-color-swatch.active::after {
|
||||
content: '✓';
|
||||
position: absolute; inset: 0;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: .7rem; font-weight: 900; color: #fff;
|
||||
text-shadow: 0 1px 3px rgba(0,0,0,.6);
|
||||
}
|
||||
.ps-color-custom {
|
||||
width: 32px; height: 32px;
|
||||
border-radius: 8px;
|
||||
padding: 0;
|
||||
border: 2px solid rgba(255,255,255,.2);
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Privacy toggle */
|
||||
.ps-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid rgba(255,255,255,.05);
|
||||
}
|
||||
.ps-toggle:last-child { border-bottom: none; }
|
||||
.ps-toggle-label { font-size: .88rem; color: rgba(255,255,255,.8); }
|
||||
.ps-toggle-sub { font-size: .75rem; color: rgba(255,255,255,.35); margin-top: 2px; }
|
||||
.ps-switch {
|
||||
position: relative;
|
||||
width: 44px; height: 24px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ps-switch input { opacity: 0; width: 0; height: 0; }
|
||||
.ps-slider {
|
||||
position: absolute; inset: 0;
|
||||
background: rgba(255,255,255,.12);
|
||||
border-radius: 24px;
|
||||
transition: background .2s;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ps-slider::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 18px; height: 18px;
|
||||
left: 3px; top: 3px;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
transition: transform .2s;
|
||||
}
|
||||
.ps-switch input:checked + .ps-slider { background: var(--ps-color, #00f5ff); }
|
||||
.ps-switch input:checked + .ps-slider::before { transform: translateX(20px); }
|
||||
|
||||
/* Save button */
|
||||
.ps-save {
|
||||
width: 100%;
|
||||
padding: 13px;
|
||||
border-radius: 12px;
|
||||
background: var(--ps-color, #00f5ff);
|
||||
color: #000;
|
||||
font-weight: 800;
|
||||
font-size: .95rem;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: opacity .2s, transform .1s;
|
||||
letter-spacing: .02em;
|
||||
}
|
||||
.ps-save:hover { opacity: .88; }
|
||||
.ps-save:active { transform: scale(.98); }
|
||||
|
||||
/* Alert */
|
||||
.ps-alert {
|
||||
border-radius: 10px;
|
||||
padding: 12px 16px;
|
||||
font-size: .85rem;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.ps-alert-success { background: rgba(63,185,80,.15); border: 1px solid rgba(63,185,80,.3); color: #7ee787; }
|
||||
.ps-alert-error { background: rgba(248,81,73,.12); border: 1px solid rgba(248,81,73,.3); color: #f85149; }
|
||||
|
||||
/* Back link */
|
||||
.ps-back {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
color: rgba(255,255,255,.45);
|
||||
font-size: .83rem;
|
||||
margin-bottom: 28px;
|
||||
text-decoration: none;
|
||||
transition: color .2s;
|
||||
}
|
||||
.ps-back:hover { color: rgba(255,255,255,.8); }
|
||||
|
||||
/* Danger zone */
|
||||
.ps-danger { border-color: rgba(248,81,73,.25); }
|
||||
.ps-danger .ps-card-title { color: rgba(248,81,73,.7); }
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.ps-banner-area { height: 140px; }
|
||||
.ps-avatar { width: 76px; height: 76px; }
|
||||
.ps-avatar-row { margin-top: -38px; }
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="ps-wrap" id="psWrap" style="--ps-color: {{ $user->profile_color ?? '#00f5ff' }}">
|
||||
|
||||
<a href="{{ route('profile') }}" class="ps-back">
|
||||
<i class="bi bi-arrow-left"></i> Profilime Dön
|
||||
</a>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="ps-alert ps-alert-success">
|
||||
<i class="bi bi-check-circle-fill"></i>{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
@if($errors->any())
|
||||
<div class="ps-alert ps-alert-error">
|
||||
<i class="bi bi-exclamation-circle-fill"></i>{{ $errors->first() }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Banner --}}
|
||||
<form method="POST" action="{{ route('profile.banner') }}" enctype="multipart/form-data" id="bannerForm">
|
||||
@csrf
|
||||
<div class="ps-banner-area" onclick="document.getElementById('bannerInput').click()" title="Kapak fotoğrafı değiştir">
|
||||
@if($user->banner_image)
|
||||
<img class="ps-banner-img" src="{{ \App\Support\MediaUrl::fromStoragePath($user->banner_image) }}" alt="Banner">
|
||||
@else
|
||||
<div class="ps-banner-img" style="background:linear-gradient(135deg,#0d0d1a 0%,#1a0a2e 50%,#0a1a1a 100%);display:flex;align-items:center;justify-content:center">
|
||||
<span style="color:rgba(255,255,255,.1);font-size:3rem"><i class="bi bi-image"></i></span>
|
||||
</div>
|
||||
@endif
|
||||
<div class="ps-banner-overlay">
|
||||
<i class="bi bi-camera" style="font-size:1.5rem"></i>
|
||||
Kapak Fotoğrafı Değiştir
|
||||
</div>
|
||||
</div>
|
||||
<input type="file" id="bannerInput" name="banner" accept="image/*" style="display:none" onchange="this.form.submit()">
|
||||
</form>
|
||||
|
||||
{{-- Avatar row --}}
|
||||
<div class="ps-avatar-row">
|
||||
<form method="POST" action="{{ route('profile.avatar') }}" enctype="multipart/form-data" id="avatarForm">
|
||||
@csrf
|
||||
<div class="ps-avatar-wrap" onclick="document.getElementById('avatarInput').click()" title="Fotoğraf değiştir">
|
||||
<div class="ps-avatar">
|
||||
@if($user->avatar)
|
||||
<img src="{{ \App\Support\MediaUrl::fromStoragePath($user->avatar) }}" alt="{{ $user->name }}">
|
||||
@else
|
||||
{{ strtoupper(substr($user->name, 0, 1)) }}
|
||||
@endif
|
||||
</div>
|
||||
<div class="ps-avatar-overlay"><i class="bi bi-camera-fill"></i></div>
|
||||
</div>
|
||||
<input type="file" id="avatarInput" name="avatar" accept="image/*" style="display:none" onchange="this.form.submit()">
|
||||
</form>
|
||||
<div class="ps-avatar-name">{{ $user->name }}</div>
|
||||
</div>
|
||||
|
||||
{{-- Ana bilgiler --}}
|
||||
<form method="POST" action="{{ route('profile.update') }}">
|
||||
@csrf
|
||||
<input type="hidden" name="profile_color" id="profileColorInput" value="{{ $user->profile_color ?? '#00f5ff' }}">
|
||||
|
||||
<div class="ps-card">
|
||||
<div class="ps-card-title"><i class="bi bi-person"></i> Temel Bilgiler</div>
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<div class="ps-field">
|
||||
<label class="ps-label">Görünen Ad *</label>
|
||||
<input type="text" name="name" class="ps-input" value="{{ old('name', $user->name) }}" required maxlength="60">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="ps-field">
|
||||
<label class="ps-label">Kullanıcı Adı <span style="opacity:.5">(opsiyonel)</span></label>
|
||||
<div style="position:relative">
|
||||
<span class="ps-prefix">@</span>
|
||||
<input type="text" name="username" class="ps-input with-prefix"
|
||||
value="{{ old('username', $user->username) }}"
|
||||
placeholder="kullanici_adi" maxlength="30"
|
||||
pattern="[a-zA-Z0-9_\-]+" title="Harf, rakam, _ veya - olabilir">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="ps-field">
|
||||
<label class="ps-label">Hakkımda <span style="opacity:.5">(max 300 karakter)</span></label>
|
||||
<textarea name="bio" class="ps-input ps-textarea" maxlength="300"
|
||||
placeholder="Kendinizden kısaca bahsedin...">{{ old('bio', $user->bio) }}</textarea>
|
||||
<div style="text-align:right;font-size:.72rem;color:rgba(255,255,255,.3);margin-top:4px">
|
||||
<span id="bioCount">{{ strlen($user->bio ?? '') }}</span>/300
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Sosyal linkler --}}
|
||||
<div class="ps-card">
|
||||
<div class="ps-card-title"><i class="bi bi-link-45deg"></i> Sosyal Bağlantılar</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<div class="ps-field">
|
||||
<label class="ps-label"><i class="bi bi-twitter-x" style="font-size:.9rem"></i> Twitter / X</label>
|
||||
<div style="position:relative">
|
||||
<span class="ps-prefix">@</span>
|
||||
<input type="text" name="twitter" class="ps-input with-prefix"
|
||||
value="{{ old('twitter', $user->twitter) }}"
|
||||
placeholder="kullanici_adi" maxlength="50">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="ps-field">
|
||||
<label class="ps-label"><i class="bi bi-instagram" style="font-size:.9rem"></i> Instagram</label>
|
||||
<div style="position:relative">
|
||||
<span class="ps-prefix">@</span>
|
||||
<input type="text" name="instagram" class="ps-input with-prefix"
|
||||
value="{{ old('instagram', $user->instagram) }}"
|
||||
placeholder="kullanici_adi" maxlength="50">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="ps-field">
|
||||
<label class="ps-label"><i class="bi bi-discord" style="font-size:.9rem"></i> Discord</label>
|
||||
<input type="text" name="discord" class="ps-input"
|
||||
value="{{ old('discord', $user->discord) }}"
|
||||
placeholder="Kullanıcı#0000 veya kullanici" maxlength="80">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="ps-field">
|
||||
<label class="ps-label"><i class="bi bi-globe2" style="font-size:.9rem"></i> Website</label>
|
||||
<input type="url" name="website" class="ps-input"
|
||||
value="{{ old('website', $user->website) }}"
|
||||
placeholder="https://..." maxlength="200">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Profil rengi --}}
|
||||
<div class="ps-card">
|
||||
<div class="ps-card-title"><i class="bi bi-palette"></i> Profil Rengi</div>
|
||||
<p style="font-size:.8rem;color:rgba(255,255,255,.4);margin-bottom:16px">
|
||||
Profil sayfasındaki vurgu rengini seç.
|
||||
</p>
|
||||
<div class="ps-color-grid">
|
||||
@php
|
||||
$colors = [
|
||||
'#00f5ff' => 'Siyan',
|
||||
'#ff2d7d' => 'Pembe',
|
||||
'#a371f7' => 'Mor',
|
||||
'#3fb950' => 'Yeşil',
|
||||
'#f0883e' => 'Turuncu',
|
||||
'#ffd700' => 'Altın',
|
||||
'#58a6ff' => 'Mavi',
|
||||
'#ff6b6b' => 'Kırmızı',
|
||||
'#e8d44d' => 'Sarı',
|
||||
'#56d364' => 'Açık Yeşil',
|
||||
];
|
||||
$currentColor = old('profile_color', $user->profile_color ?? '#00f5ff');
|
||||
@endphp
|
||||
@foreach($colors as $hex => $name)
|
||||
<div class="ps-color-swatch {{ $currentColor === $hex ? 'active' : '' }}"
|
||||
style="background:{{ $hex }}"
|
||||
title="{{ $name }}"
|
||||
onclick="setColor('{{ $hex }}', this)"></div>
|
||||
@endforeach
|
||||
<input type="color" class="ps-color-custom" id="customColorPicker"
|
||||
value="{{ $currentColor }}"
|
||||
title="Özel renk"
|
||||
onchange="setColor(this.value, null)">
|
||||
</div>
|
||||
<div style="margin-top:12px;font-size:.78rem;color:rgba(255,255,255,.3)">
|
||||
Seçili: <span id="colorLabel" style="color:var(--ps-color)">{{ $currentColor }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Gizlilik --}}
|
||||
<div class="ps-card">
|
||||
<div class="ps-card-title"><i class="bi bi-shield-check"></i> Gizlilik</div>
|
||||
<div class="ps-toggle">
|
||||
<div>
|
||||
<div class="ps-toggle-label">İzleme Listemi Göster</div>
|
||||
<div class="ps-toggle-sub">Diğer kullanıcılar listenizi görebilir</div>
|
||||
</div>
|
||||
<label class="ps-switch">
|
||||
<input type="checkbox" name="show_watchlist" value="1" {{ $user->show_watchlist ? 'checked' : '' }}>
|
||||
<span class="ps-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="ps-toggle">
|
||||
<div>
|
||||
<div class="ps-toggle-label">İzleme Aktivitemi Göster</div>
|
||||
<div class="ps-toggle-sub">Izleme heatmap ve geçmişi herkese açık</div>
|
||||
</div>
|
||||
<label class="ps-switch">
|
||||
<input type="checkbox" name="show_activity" value="1" {{ $user->show_activity ? 'checked' : '' }}>
|
||||
<span class="ps-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="ps-save">
|
||||
<i class="bi bi-check2 me-2"></i>Değişiklikleri Kaydet
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{{-- Şifre değişikliği --}}
|
||||
<form method="POST" action="{{ route('profile.password') }}" style="margin-top:20px">
|
||||
@csrf
|
||||
<div class="ps-card">
|
||||
<div class="ps-card-title"><i class="bi bi-lock"></i> Şifre Değiştir</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-12">
|
||||
<div class="ps-field">
|
||||
<label class="ps-label">Mevcut Şifre</label>
|
||||
<input type="password" name="current_password" class="ps-input" required autocomplete="current-password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="ps-field">
|
||||
<label class="ps-label">Yeni Şifre</label>
|
||||
<input type="password" name="password" class="ps-input" required autocomplete="new-password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="ps-field">
|
||||
<label class="ps-label">Yeni Şifre (Tekrar)</label>
|
||||
<input type="password" name="password_confirmation" class="ps-input" required autocomplete="new-password">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="ps-save" style="margin-top:16px;background:rgba(255,255,255,.12);color:#fff">
|
||||
<i class="bi bi-lock me-2"></i>Şifreyi Güncelle
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{{-- ── Premium Kozmetik Ayarları ────────────────────────────────── --}}
|
||||
@if(auth()->user()->isPremium())
|
||||
<form method="POST" action="{{ route('premium.cosmetics.save') }}">
|
||||
@csrf
|
||||
@php $u = auth()->user(); @endphp
|
||||
|
||||
<div class="ps-card" style="border:1px solid rgba(0,245,255,.18);background:linear-gradient(135deg,rgba(0,245,255,.03),rgba(184,77,255,.03))">
|
||||
<div class="ps-card-title" style="color:#00f5ff">
|
||||
<i class="bi bi-stars"></i> Premium Kozmetik
|
||||
<span style="font-size:.72rem;font-weight:400;color:rgba(0,245,255,.6);margin-left:8px">Sadece premium üyelere özel</span>
|
||||
</div>
|
||||
|
||||
{{-- GIF Avatar --}}
|
||||
@if($u->hasPerk('gif_avatar'))
|
||||
<div class="ps-field" style="margin-bottom:20px">
|
||||
<label class="ps-label"><i class="bi bi-image-fill" style="color:#00f5ff"></i> GIF Profil Fotoğrafı</label>
|
||||
<input type="hidden" name="gif_avatar" id="gifAvatarInput" value="{{ old('gif_avatar', $u->gif_avatar) }}">
|
||||
|
||||
{{-- Mevcut seçim önizleme --}}
|
||||
<div id="gifAvatarPreview" style="margin-bottom:10px;{{ $u->gif_avatar ? '' : 'display:none' }}">
|
||||
<div style="display:flex;align-items:center;gap:10px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.1);border-radius:12px;padding:10px 14px;">
|
||||
<img id="gifAvatarThumb" src="{{ $u->gif_avatar ?? '' }}" alt="GIF"
|
||||
style="width:56px;height:56px;border-radius:10px;object-fit:cover;border:1px solid rgba(255,255,255,.12)">
|
||||
<div style="flex:1;min-width:0">
|
||||
<div style="font-size:.78rem;color:rgba(255,255,255,.7);margin-bottom:4px">Seçili GIF</div>
|
||||
<div id="gifAvatarUrl" style="font-size:.65rem;color:rgba(255,255,255,.3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis">{{ $u->gif_avatar ?? '' }}</div>
|
||||
</div>
|
||||
<button type="button" onclick="clearGifAvatar()" style="background:rgba(255,80,80,.12);border:1px solid rgba(255,80,80,.25);color:#ff5050;border-radius:8px;padding:5px 10px;font-size:.75rem;cursor:pointer;flex-shrink:0">
|
||||
<i class="bi bi-x-lg"></i> Kaldır
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Arama --}}
|
||||
<div style="display:flex;gap:8px;margin-bottom:8px">
|
||||
<input type="text" id="gifAvatarSearch" class="ps-input" placeholder="anime gif ara..." style="flex:1"
|
||||
oninput="debounceGifSearch(this.value)">
|
||||
<button type="button" onclick="debounceGifSearch(document.getElementById('gifAvatarSearch').value,true)"
|
||||
style="background:rgba(0,245,255,.1);border:1px solid rgba(0,245,255,.25);color:#00f5ff;border-radius:10px;padding:0 14px;font-size:.85rem;cursor:pointer;flex-shrink:0;white-space:nowrap">
|
||||
<i class="bi bi-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{-- Sonuç grid --}}
|
||||
<div id="gifAvatarGrid" style="display:grid;grid-template-columns:repeat(4,1fr);gap:6px;max-height:280px;overflow-y:auto;scrollbar-width:thin"></div>
|
||||
<div id="gifAvatarMsg" style="font-size:.72rem;color:rgba(255,255,255,.3);margin-top:6px;text-align:center"></div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Yorum Arkaplanı --}}
|
||||
@if($u->hasPerk('comment_bg'))
|
||||
<div class="ps-field" style="margin-bottom:24px">
|
||||
<label class="ps-label"><i class="bi bi-fire" style="color:#ff6b35"></i> Yorum Arkaplanı Efekti</label>
|
||||
<div class="prem-picker" style="grid-template-columns:repeat(auto-fill,minmax(100px,1fr))">
|
||||
<label class="prem-pick-item {{ !$u->comment_bg ? 'active' : '' }}">
|
||||
<input type="radio" name="comment_bg" value="">
|
||||
<div style="width:100%;height:36px;border-radius:7px;background:rgba(255,255,255,.05);display:flex;align-items:center;justify-content:center;font-size:.75rem;color:rgba(255,255,255,.3)">— Yok —</div>
|
||||
<span class="prem-pick-lbl">Yok</span>
|
||||
</label>
|
||||
@foreach(\App\Services\PremiumFeatures::COMMENT_BACKGROUNDS as $key => $bg)
|
||||
<label class="prem-pick-item {{ $u->comment_bg === $key ? 'active' : '' }}">
|
||||
<input type="radio" name="comment_bg" value="{{ $key }}">
|
||||
<div class="comment-wrap" data-bg="{{ $key }}" style="width:100%;min-height:36px;border-radius:7px;display:flex;align-items:center;justify-content:center;font-size:.75rem;overflow:hidden">
|
||||
<span>{{ $bg['label'] }}</span>
|
||||
</div>
|
||||
<span class="prem-pick-lbl">{{ $bg['label'] }}</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Kullanıcı Adı Rengi --}}
|
||||
@if($u->hasPerk('username_color'))
|
||||
<div class="ps-field" style="margin-bottom:24px">
|
||||
<label class="ps-label"><i class="bi bi-palette-fill" style="color:#b84dff"></i> Kullanıcı Adı Rengi</label>
|
||||
<div class="prem-picker" style="grid-template-columns:repeat(auto-fill,minmax(120px,1fr))">
|
||||
<label class="prem-pick-item {{ !$u->username_color ? 'active' : '' }}">
|
||||
<input type="radio" name="username_color" value="">
|
||||
<span class="prem-pick-preview" style="color:rgba(200,200,220,.55)">{{ $u->name }}</span>
|
||||
<span class="prem-pick-lbl">Varsayılan</span>
|
||||
</label>
|
||||
@foreach(\App\Services\PremiumFeatures::USERNAME_COLORS as $key => $color)
|
||||
<label class="prem-pick-item {{ $u->username_color === $key ? 'active' : '' }}">
|
||||
<input type="radio" name="username_color" value="{{ $key }}">
|
||||
<span class="prem-pick-preview username-color-{{ $key }}">{{ $u->name }}</span>
|
||||
<span class="prem-pick-lbl">{{ $color['label'] }}</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Profil Çerçevesi --}}
|
||||
@if($u->hasPerk('profile_frame'))
|
||||
<div class="ps-field" style="margin-bottom:24px">
|
||||
<label class="ps-label"><i class="bi bi-circle-fill" style="color:#ffd700"></i> Profil Çerçevesi</label>
|
||||
<div class="prem-picker" style="grid-template-columns:repeat(auto-fill,minmax(82px,1fr))">
|
||||
<label class="prem-pick-item {{ !$u->profile_frame ? 'active' : '' }}">
|
||||
<input type="radio" name="profile_frame" value="">
|
||||
<div style="width:48px;height:48px;border-radius:50%;background:rgba(255,255,255,.07);display:flex;align-items:center;justify-content:center;font-weight:800;font-size:1.1rem;color:rgba(255,255,255,.3)">{{ mb_substr($u->name,0,1) }}</div>
|
||||
<span class="prem-pick-lbl">Yok</span>
|
||||
</label>
|
||||
@foreach(\App\Services\PremiumFeatures::PROFILE_FRAMES as $key => $frame)
|
||||
<label class="prem-pick-item {{ $u->profile_frame === $key ? 'active' : '' }}">
|
||||
<input type="radio" name="profile_frame" value="{{ $key }}">
|
||||
<div class="avatar-wrap" style="width:48px;height:48px">
|
||||
<div class="avatar-frame frame-{{ $key }}"></div>
|
||||
<div style="width:48px;height:48px;border-radius:50%;background:rgba(255,255,255,.12);display:flex;align-items:center;justify-content:center;font-weight:800;font-size:1.1rem;color:rgba(255,255,255,.6);position:relative;z-index:3">{{ mb_substr($u->name,0,1) }}</div>
|
||||
</div>
|
||||
<span class="prem-pick-lbl">{{ $frame['label'] }}</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Özel Rozet/Unvan --}}
|
||||
@if($u->hasPerk('profile_badge'))
|
||||
<div class="ps-field" style="margin-bottom:24px">
|
||||
<label class="ps-label"><i class="bi bi-award-fill" style="color:#ffd700"></i> Özel Rozet / Unvan</label>
|
||||
<input type="text" name="profile_badge" class="ps-input" value="{{ old('profile_badge', $u->profile_badge) }}"
|
||||
placeholder="Anime Uzmanı" maxlength="32">
|
||||
<div style="font-size:.72rem;color:rgba(255,255,255,.35);margin-top:4px">Max 32 karakter. Kullanıcı adının yanında görünür.</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Profil Müziği --}}
|
||||
@if($u->hasPerk('profile_music'))
|
||||
<div class="ps-field" style="margin-bottom:24px">
|
||||
<label class="ps-label"><i class="bi bi-music-note-beamed" style="color:#00f5ff"></i> Profil Müziği URL</label>
|
||||
<input type="url" name="profile_music_url" class="ps-input" value="{{ old('profile_music_url', $u->profile_music_url) }}"
|
||||
placeholder="https://www.youtube.com/watch?v=... veya direkt MP3 URL">
|
||||
<div style="font-size:.72rem;color:rgba(255,255,255,.35);margin-top:4px">YouTube, SoundCloud veya direkt ses dosyası URL'si. Profilini ziyaret edenlere çalar.</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Profil Arka Planı --}}
|
||||
@if($u->hasPerk('profile_bg'))
|
||||
<div class="ps-field" style="margin-bottom:24px">
|
||||
<label class="ps-label"><i class="bi bi-stars" style="color:#b84dff"></i> Profil Arka Planı</label>
|
||||
<div class="prem-picker" style="grid-template-columns:repeat(auto-fill,minmax(100px,1fr))">
|
||||
<label class="prem-pick-item {{ !$u->profile_bg ? 'active' : '' }}">
|
||||
<input type="radio" name="profile_bg" value="">
|
||||
<div style="width:100%;height:36px;border-radius:7px;background:rgba(255,255,255,.05);display:flex;align-items:center;justify-content:center;font-size:.75rem;color:rgba(255,255,255,.3)">— Yok —</div>
|
||||
<span class="prem-pick-lbl">Varsayılan</span>
|
||||
</label>
|
||||
@foreach(\App\Services\PremiumFeatures::PROFILE_BACKGROUNDS as $key => $bg)
|
||||
@php [$c1,$c2] = explode(',', $bg['preview']); @endphp
|
||||
<label class="prem-pick-item {{ $u->profile_bg === $key ? 'active' : '' }}">
|
||||
<input type="radio" name="profile_bg" value="{{ $key }}">
|
||||
<div style="width:100%;height:36px;border-radius:7px;background:linear-gradient(135deg,{{ $c1 }},{{ $c2 }});display:flex;align-items:center;justify-content:center;font-size:.72rem;color:rgba(255,255,255,.8);font-weight:700">{{ $bg['label'] }}</div>
|
||||
<span class="prem-pick-lbl">{{ $bg['label'] }}</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Yorum Aura / Parıltı --}}
|
||||
@if($u->hasPerk('comment_glow'))
|
||||
<div class="ps-field" style="margin-bottom:24px">
|
||||
<label class="ps-label"><i class="bi bi-brightness-high-fill" style="color:#00f5ff"></i> Yorum Aura / Parıltı</label>
|
||||
<div class="prem-picker" style="grid-template-columns:repeat(auto-fill,minmax(90px,1fr))">
|
||||
<label class="prem-pick-item {{ !$u->comment_glow ? 'active' : '' }}">
|
||||
<input type="radio" name="comment_glow" value="">
|
||||
<div style="width:44px;height:44px;border-radius:50%;border:1.5px solid rgba(255,255,255,.15);display:flex;align-items:center;justify-content:center;font-size:.7rem;color:rgba(255,255,255,.3)">—</div>
|
||||
<span class="prem-pick-lbl">Yok</span>
|
||||
</label>
|
||||
@foreach(\App\Services\PremiumFeatures::COMMENT_GLOWS as $key => $glow)
|
||||
<label class="prem-pick-item {{ $u->comment_glow === $key ? 'active' : '' }}">
|
||||
<input type="radio" name="comment_glow" value="{{ $key }}">
|
||||
<div style="width:44px;height:44px;border-radius:50%;border:1.5px solid {{ $glow['color'] }};box-shadow:0 0 12px {{ $glow['color'] }},0 0 24px {{ $glow['color'] }}44;background:{{ $glow['color'] }}22"></div>
|
||||
<span class="prem-pick-lbl">{{ $glow['label'] }}</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Kullanıcı Adı Animasyonu --}}
|
||||
@if($u->hasPerk('username_effect'))
|
||||
<div class="ps-field" style="margin-bottom:24px">
|
||||
<label class="ps-label"><i class="bi bi-lightning-charge-fill" style="color:#ffd700"></i> Kullanıcı Adı Animasyonu</label>
|
||||
<div class="prem-picker" style="grid-template-columns:repeat(auto-fill,minmax(110px,1fr))">
|
||||
<label class="prem-pick-item {{ !$u->username_effect ? 'active' : '' }}">
|
||||
<input type="radio" name="username_effect" value="">
|
||||
<span class="prem-pick-preview" style="color:rgba(200,200,220,.6)">{{ $u->name }}</span>
|
||||
<span class="prem-pick-lbl">Yok</span>
|
||||
</label>
|
||||
@foreach(\App\Services\PremiumFeatures::USERNAME_EFFECTS as $key => $eff)
|
||||
<label class="prem-pick-item {{ $u->username_effect === $key ? 'active' : '' }}">
|
||||
<input type="radio" name="username_effect" value="{{ $key }}">
|
||||
<span class="prem-pick-preview username-effect-{{ $key }}" @if($key==='glitch') data-text="{{ $u->name }}" @endif>{{ $u->name }}</span>
|
||||
<span class="prem-pick-lbl">{{ $eff['label'] }}</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Yorum İmzası --}}
|
||||
@if($u->hasPerk('comment_signature'))
|
||||
<div class="ps-field" style="margin-bottom:24px">
|
||||
<label class="ps-label"><i class="bi bi-pen-fill" style="color:#ff9ec4"></i> Yorum İmzası</label>
|
||||
<input type="text" name="comment_signature" class="ps-input" value="{{ old('comment_signature', $u->comment_signature) }}"
|
||||
placeholder="— Anime severinden sevgiyle ✨" maxlength="100">
|
||||
<div style="font-size:.72rem;color:rgba(255,255,255,.35);margin-top:4px">Max 100 karakter. Her yorumun altında küçük yazıyla görünür.</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Sayfa Giriş Efekti --}}
|
||||
@if($u->hasPerk('entry_effect'))
|
||||
<div class="ps-field" style="margin-bottom:24px">
|
||||
<label class="ps-label"><i class="bi bi-play-circle-fill" style="color:#3fb950"></i> Sayfa Giriş Efekti</label>
|
||||
<div class="prem-picker" style="grid-template-columns:repeat(auto-fill,minmax(100px,1fr))">
|
||||
<label class="prem-pick-item {{ !$u->entry_effect ? 'active' : '' }}">
|
||||
<input type="radio" name="entry_effect" value="">
|
||||
<div style="font-size:1.4rem">🚫</div>
|
||||
<span class="prem-pick-lbl">Yok</span>
|
||||
</label>
|
||||
@foreach(\App\Services\PremiumFeatures::ENTRY_EFFECTS as $key => $eff)
|
||||
<label class="prem-pick-item {{ $u->entry_effect === $key ? 'active' : '' }}">
|
||||
<input type="radio" name="entry_effect" value="{{ $key }}">
|
||||
<div style="font-size:1.4rem">{{ ['fade'=>'✨','slide'=>'⬆️','zoom'=>'🔍','glitch'=>'⚡','wave'=>'🌊'][$key] ?? '✨' }}</div>
|
||||
<span class="prem-pick-lbl">{{ $eff['label'] }}</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Animasyonlu Banner --}}
|
||||
@if($u->hasPerk('animated_banner'))
|
||||
<div class="ps-field" style="margin-bottom:24px">
|
||||
<div class="ps-toggle" style="padding:14px 16px;background:rgba(255,255,255,.04);border-radius:12px;border:1px solid rgba(255,255,255,.08);border-bottom:1px solid rgba(255,255,255,.08)">
|
||||
<div>
|
||||
<div class="ps-toggle-label" style="color:#fff"><i class="bi bi-image-alt" style="color:#00f5ff;margin-right:6px"></i> Animasyonlu Profil Bannerı</div>
|
||||
<div class="ps-toggle-sub">Profil bannerın parıltılı parçacık efektiyle canlanır</div>
|
||||
</div>
|
||||
<label class="ps-switch">
|
||||
<input type="checkbox" name="animated_banner" value="1" {{ $u->animated_banner ? 'checked' : '' }}>
|
||||
<span class="ps-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<button type="submit" class="ps-save" style="background:linear-gradient(135deg,rgba(0,245,255,.15),rgba(184,77,255,.15));border:1px solid rgba(0,245,255,.3);color:#00f5ff">
|
||||
<i class="bi bi-stars me-2"></i>Premium Ayarları Kaydet
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@else
|
||||
{{-- Premium değil — yükseltme banner'ı --}}
|
||||
<div class="ps-card" style="border:1px solid rgba(255,215,0,.2);background:linear-gradient(135deg,rgba(255,215,0,.04),rgba(255,140,0,.04));text-align:center;padding:32px 24px">
|
||||
<div style="font-size:2rem;margin-bottom:12px">✨</div>
|
||||
<div style="font-weight:700;font-size:1rem;color:#ffd700;margin-bottom:6px">Premium Kozmetikler</div>
|
||||
<div style="font-size:.85rem;color:rgba(255,255,255,.5);margin-bottom:16px">
|
||||
Animasyonlu yorum arkaplanları, renkli kullanıcı adı, profil çerçevesi ve daha fazlası için premium üye ol.
|
||||
</div>
|
||||
<a href="{{ route('premium.plans') }}" class="ps-save" style="display:inline-flex;background:linear-gradient(135deg,#ff8c00,#ffd700);color:#000;font-weight:800;text-decoration:none;padding:10px 28px;border-radius:10px">
|
||||
<i class="bi bi-stars me-2"></i>Premium'a Geç
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
// Premium picker: radio seçilince parent label'a .active sınıfı ekle
|
||||
document.querySelectorAll('.prem-picker input[type="radio"]').forEach(radio => {
|
||||
radio.addEventListener('change', () => {
|
||||
const picker = radio.closest('.prem-picker');
|
||||
picker.querySelectorAll('.prem-pick-item').forEach(el => el.classList.remove('active'));
|
||||
radio.closest('.prem-pick-item').classList.add('active');
|
||||
});
|
||||
});
|
||||
|
||||
const wrap = document.getElementById('psWrap');
|
||||
|
||||
function setColor(hex, el) {
|
||||
wrap.style.setProperty('--ps-color', hex);
|
||||
document.getElementById('profileColorInput').value = hex;
|
||||
document.getElementById('colorLabel').textContent = hex;
|
||||
document.getElementById('colorLabel').style.color = hex;
|
||||
document.getElementById('customColorPicker').value = hex;
|
||||
|
||||
document.querySelectorAll('.ps-color-swatch').forEach(s => s.classList.remove('active'));
|
||||
if (el) el.classList.add('active');
|
||||
}
|
||||
|
||||
// Bio karakter sayacı
|
||||
const bioTextarea = document.querySelector('[name="bio"]');
|
||||
const bioCount = document.getElementById('bioCount');
|
||||
if (bioTextarea) {
|
||||
bioTextarea.addEventListener('input', () => {
|
||||
bioCount.textContent = bioTextarea.value.length;
|
||||
});
|
||||
}
|
||||
|
||||
// Banner önizleme
|
||||
document.getElementById('bannerInput').addEventListener('change', function() {
|
||||
const file = this.files[0];
|
||||
if (!file) return;
|
||||
const reader = new FileReader();
|
||||
reader.onload = e => {
|
||||
const img = document.querySelector('.ps-banner-img');
|
||||
if (img.tagName === 'IMG') {
|
||||
img.src = e.target.result;
|
||||
} else {
|
||||
const newImg = document.createElement('img');
|
||||
newImg.className = 'ps-banner-img';
|
||||
newImg.src = e.target.result;
|
||||
img.replaceWith(newImg);
|
||||
}
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
// Avatar önizleme
|
||||
document.getElementById('avatarInput').addEventListener('change', function() {
|
||||
const file = this.files[0];
|
||||
if (!file) return;
|
||||
const reader = new FileReader();
|
||||
reader.onload = e => {
|
||||
const avatarDiv = document.querySelector('.ps-avatar');
|
||||
avatarDiv.innerHTML = `<img src="${e.target.result}" alt="Avatar">`;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
// ── GIF Avatar Picker ─────────────────────────────────────────────────────
|
||||
let gifSearchTimer = null;
|
||||
|
||||
function debounceGifSearch(q, immediate = false) {
|
||||
clearTimeout(gifSearchTimer);
|
||||
if (!q.trim()) { document.getElementById('gifAvatarGrid').innerHTML = ''; return; }
|
||||
const delay = immediate ? 0 : 500;
|
||||
gifSearchTimer = setTimeout(() => searchGifAvatar(q.trim()), delay);
|
||||
}
|
||||
|
||||
async function searchGifAvatar(q) {
|
||||
const grid = document.getElementById('gifAvatarGrid');
|
||||
const msg = document.getElementById('gifAvatarMsg');
|
||||
grid.innerHTML = '<div style="grid-column:1/-1;text-align:center;padding:20px;color:rgba(255,255,255,.3);font-size:.8rem"><i class="bi bi-arrow-repeat"></i> Aranıyor...</div>';
|
||||
msg.textContent = '';
|
||||
try {
|
||||
const res = await fetch(`/comments/gif-search?q=${encodeURIComponent(q)}`);
|
||||
const data = await res.json();
|
||||
const gifs = data.results ?? [];
|
||||
if (!gifs.length) {
|
||||
grid.innerHTML = '';
|
||||
msg.textContent = 'Sonuç bulunamadı.';
|
||||
return;
|
||||
}
|
||||
grid.innerHTML = gifs.map(g => `
|
||||
<div onclick="selectGifAvatar('${g.url.replace(/'/g,"\\'")}','${g.preview.replace(/'/g,"\\'")}','${(g.url).replace(/'/g,"\\'")}' )"
|
||||
style="cursor:pointer;border-radius:8px;overflow:hidden;border:2px solid transparent;transition:border-color .15s,transform .15s;aspect-ratio:1;background:#111"
|
||||
onmouseover="this.style.borderColor='rgba(0,245,255,.5)';this.style.transform='scale(1.04)'"
|
||||
onmouseout="this.style.borderColor='transparent';this.style.transform='scale(1)'">
|
||||
<img src="${g.preview}" alt="" loading="lazy" style="width:100%;height:100%;object-fit:cover;display:block">
|
||||
</div>`).join('');
|
||||
} catch(e) {
|
||||
grid.innerHTML = '';
|
||||
msg.textContent = 'Arama başarısız oldu.';
|
||||
}
|
||||
}
|
||||
|
||||
function selectGifAvatar(url, preview) {
|
||||
document.getElementById('gifAvatarInput').value = url;
|
||||
document.getElementById('gifAvatarThumb').src = preview;
|
||||
document.getElementById('gifAvatarUrl').textContent = url;
|
||||
document.getElementById('gifAvatarPreview').style.display = '';
|
||||
document.getElementById('gifAvatarGrid').innerHTML = '';
|
||||
document.getElementById('gifAvatarSearch').value = '';
|
||||
document.getElementById('gifAvatarMsg').textContent = '';
|
||||
}
|
||||
|
||||
function clearGifAvatar() {
|
||||
document.getElementById('gifAvatarInput').value = '';
|
||||
document.getElementById('gifAvatarPreview').style.display = 'none';
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,825 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', $user->name . ' — Profil — Animexe')
|
||||
@push('styles')
|
||||
<style>
|
||||
/* ═══════════════════════════ PROFILE ═══════════════════════════ */
|
||||
|
||||
/* ── Hero banner ──────────────────────────────────────────────── */
|
||||
.pr-hero{
|
||||
position:relative;overflow:hidden;
|
||||
background:#05050e;
|
||||
padding-bottom:0;
|
||||
}
|
||||
.pr-hero-bg{
|
||||
position:absolute;inset:0;
|
||||
background:
|
||||
radial-gradient(ellipse 80% 60% at 20% 50%, rgba(0,245,255,.06), transparent),
|
||||
radial-gradient(ellipse 60% 80% at 80% 30%, rgba(255,45,125,.05), transparent);
|
||||
}
|
||||
.pr-hero-inner{
|
||||
position:relative;z-index:1;
|
||||
max-width:960px;margin:0 auto;
|
||||
padding:calc(var(--nav-h) + 32px) 24px 0;
|
||||
}
|
||||
.pr-top{display:flex;align-items:flex-start;gap:20px;flex-wrap:wrap;margin-bottom:28px}
|
||||
.pr-top-main{display:flex;align-items:flex-end;gap:20px;flex:1;min-width:0}
|
||||
|
||||
/* ── Avatar ───────────────────────────────────────────────────── */
|
||||
.pr-avatar{
|
||||
width:96px;height:96px;border-radius:24px;flex-shrink:0;
|
||||
background:linear-gradient(135deg,var(--accent2),var(--accent));
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
font-size:2.4rem;font-weight:900;color:#fff;overflow:hidden;
|
||||
box-shadow:0 0 0 3px rgba(0,245,255,.2),0 16px 48px rgba(0,0,0,.5);
|
||||
}
|
||||
.pr-info{flex:1;min-width:0;padding-bottom:4px}
|
||||
.pr-name{font-size:1.7rem;font-weight:900;color:#fff;line-height:1.1;margin-bottom:4px}
|
||||
.pr-handle{font-size:.84rem;color:rgba(255,255,255,.35);margin-bottom:10px}
|
||||
.pr-badges{display:flex;gap:7px;flex-wrap:wrap}
|
||||
.pbadge{padding:4px 12px;border-radius:20px;font-size:.7rem;font-weight:700;letter-spacing:.05em;display:inline-flex;align-items:center;gap:5px}
|
||||
.pbadge-admin{background:rgba(255,45,125,.15);border:1px solid rgba(255,45,125,.35);color:var(--accent)}
|
||||
.pbadge-premium{background:rgba(255,208,0,.12);border:1px solid rgba(255,208,0,.3);color:#ffd700}
|
||||
.pbadge-member{background:rgba(0,245,255,.07);border:1px solid rgba(0,245,255,.2);color:var(--accent2)}
|
||||
|
||||
/* ── Stat pills ───────────────────────────────────────────────── */
|
||||
.pr-stats{
|
||||
display:flex;gap:6px;flex-wrap:wrap;
|
||||
padding:20px 0 0;
|
||||
border-top:1px solid rgba(255,255,255,.06);
|
||||
margin-top:8px;
|
||||
}
|
||||
.pr-stat{
|
||||
display:flex;flex-direction:column;align-items:center;
|
||||
padding:10px 20px;border-radius:12px;
|
||||
background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.07);
|
||||
min-width:80px;flex:1;
|
||||
}
|
||||
.pr-stat .v{font-size:1.25rem;font-weight:800;color:#fff;line-height:1}
|
||||
.pr-stat .l{font-size:.62rem;text-transform:uppercase;letter-spacing:.1em;color:rgba(255,255,255,.35);margin-top:4px;font-weight:600}
|
||||
|
||||
/* ── Tab nav ──────────────────────────────────────────────────── */
|
||||
.pr-tabs{
|
||||
display:flex;gap:2px;
|
||||
border-top:1px solid rgba(255,255,255,.06);
|
||||
margin-top:20px;
|
||||
overflow-x:auto;scrollbar-width:none;
|
||||
}
|
||||
.pr-tabs::-webkit-scrollbar{display:none}
|
||||
.pr-tab{
|
||||
padding:12px 18px;background:none;border:none;
|
||||
border-bottom:2px solid transparent;
|
||||
color:rgba(255,255,255,.35);font-size:.82rem;font-weight:600;
|
||||
cursor:pointer;font-family:inherit;transition:all .15s;
|
||||
white-space:nowrap;flex-shrink:0;display:flex;align-items:center;gap:6px;
|
||||
margin-bottom:-1px;
|
||||
}
|
||||
.pr-tab:hover{color:rgba(255,255,255,.65)}
|
||||
.pr-tab.on{color:var(--accent2);border-bottom-color:var(--accent2)}
|
||||
|
||||
/* ── Body ─────────────────────────────────────────────────────── */
|
||||
.pr-body{max-width:960px;margin:0 auto;padding:32px 24px 64px}
|
||||
.pr-pane{display:none}
|
||||
.pr-pane.on{display:block}
|
||||
|
||||
/* ── Section header ───────────────────────────────────────────── */
|
||||
.pr-sec-h{
|
||||
font-size:.68rem;text-transform:uppercase;letter-spacing:.12em;
|
||||
color:rgba(255,255,255,.3);font-weight:700;
|
||||
margin-bottom:16px;display:flex;align-items:center;gap:8px;
|
||||
}
|
||||
.pr-sec-h::before{content:'';width:3px;height:14px;background:linear-gradient(180deg,var(--accent2),var(--accent));border-radius:2px}
|
||||
|
||||
/* ── Continue watching cards ──────────────────────────────────── */
|
||||
.cw-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:12px}
|
||||
.cw-card{
|
||||
border-radius:10px;overflow:hidden;
|
||||
background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.07);
|
||||
text-decoration:none;display:block;
|
||||
transition:transform .15s,border-color .15s;
|
||||
}
|
||||
.cw-card:hover{transform:translateY(-3px);border-color:rgba(0,245,255,.25)}
|
||||
.cw-thumb{position:relative;aspect-ratio:2/3;overflow:hidden}
|
||||
.cw-thumb img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .3s}
|
||||
.cw-card:hover .cw-thumb img{transform:scale(1.05)}
|
||||
.cw-thumb-ph{width:100%;height:100%;background:rgba(255,255,255,.04);display:flex;align-items:center;justify-content:center;color:rgba(255,255,255,.2);font-size:2rem}
|
||||
.cw-grad{position:absolute;inset:0;background:linear-gradient(to top,rgba(0,0,0,.85) 0%,transparent 55%)}
|
||||
.cw-play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:38px;height:38px;border-radius:50%;background:rgba(255,45,125,.85);display:flex;align-items:center;justify-content:center}
|
||||
.cw-play i{color:#fff;font-size:.95rem}
|
||||
.cw-progress{position:absolute;bottom:28px;left:10px;right:10px}
|
||||
.cw-prog-bar{height:3px;background:rgba(255,255,255,.2);border-radius:2px;overflow:hidden}
|
||||
.cw-prog-fill{height:100%;background:var(--accent);border-radius:2px}
|
||||
.cw-ep{position:absolute;bottom:8px;left:10px;font-size:.62rem;color:rgba(255,255,255,.6);font-weight:600}
|
||||
.cw-info{padding:8px 10px}
|
||||
.cw-info-title{font-size:.76rem;font-weight:600;color:rgba(255,255,255,.8);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||
|
||||
/* ── Achievement grid ─────────────────────────────────────────── */
|
||||
.ach-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:10px}
|
||||
.ach-card{
|
||||
display:flex;align-items:center;gap:14px;
|
||||
background:rgba(255,255,255,.03);
|
||||
border:1px solid rgba(255,255,255,.07);
|
||||
border-radius:12px;padding:14px 16px;
|
||||
transition:border-color .15s;
|
||||
}
|
||||
.ach-card.earned{background:rgba(255,255,255,.05)}
|
||||
.ach-card:not(.earned){opacity:.35}
|
||||
.ach-icon-wrap{width:44px;height:44px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:1.4rem;flex-shrink:0}
|
||||
.ach-body .ach-title{font-size:.85rem;font-weight:700;color:#fff;margin-bottom:2px}
|
||||
.ach-body .ach-desc{font-size:.72rem;color:rgba(255,255,255,.35);line-height:1.4}
|
||||
.ach-body .ach-date{font-size:.66rem;margin-top:4px;font-weight:600}
|
||||
|
||||
/* ── Watchlist tabs ───────────────────────────────────────────── */
|
||||
.wl-filter{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:20px}
|
||||
.wl-filter-btn{
|
||||
padding:6px 14px;border-radius:20px;border:1px solid rgba(255,255,255,.1);
|
||||
background:none;color:rgba(255,255,255,.45);font-size:.78rem;font-weight:600;
|
||||
cursor:pointer;font-family:inherit;transition:all .15s;
|
||||
}
|
||||
.wl-filter-btn:hover{border-color:rgba(255,255,255,.25);color:rgba(255,255,255,.7)}
|
||||
.wl-filter-btn.on{background:rgba(0,245,255,.1);border-color:rgba(0,245,255,.3);color:var(--accent2)}
|
||||
.wl-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:10px}
|
||||
.wl-card{
|
||||
border-radius:9px;overflow:hidden;text-decoration:none;display:block;
|
||||
background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.07);
|
||||
transition:transform .15s,border-color .15s;
|
||||
}
|
||||
.wl-card:hover{transform:translateY(-2px);border-color:rgba(255,255,255,.18)}
|
||||
.wl-card img{width:100%;aspect-ratio:2/3;object-fit:cover;display:block}
|
||||
.wl-card-ph{aspect-ratio:2/3;background:rgba(255,255,255,.04);display:flex;align-items:center;justify-content:center;color:rgba(255,255,255,.2)}
|
||||
.wl-card-title{padding:7px 8px;font-size:.72rem;font-weight:600;color:rgba(255,255,255,.7);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||
|
||||
/* ── Heatmap ──────────────────────────────────────────────────── */
|
||||
.heatmap-wrap{
|
||||
background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.07);
|
||||
border-radius:14px;padding:20px 24px;
|
||||
}
|
||||
.heatmap-scroll{overflow-x:auto;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.1) transparent;padding-bottom:6px}
|
||||
.heatmap-grid{display:flex;gap:3px;min-width:max-content}
|
||||
.hm-col{display:flex;flex-direction:column;gap:3px}
|
||||
.hm-cell{width:13px;height:13px;border-radius:3px}
|
||||
.heatmap-legend{display:flex;align-items:center;gap:10px;margin-top:14px;font-size:.7rem;color:rgba(255,255,255,.3)}
|
||||
.heatmap-legend-cells{display:flex;gap:3px;align-items:center}
|
||||
.heatmap-stats{display:flex;gap:20px;margin-top:12px;font-size:.78rem;color:rgba(255,255,255,.4)}
|
||||
|
||||
/* ── Notes ────────────────────────────────────────────────────── */
|
||||
.note-card{
|
||||
background:rgba(255,255,255,.03);border:1px solid rgba(255,215,0,.12);
|
||||
border-radius:12px;padding:16px 18px;margin-bottom:10px;
|
||||
}
|
||||
.note-meta{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:8px}
|
||||
.note-anime{font-size:.8rem;font-weight:700;color:var(--accent2);text-decoration:none}
|
||||
.note-anime:hover{text-decoration:underline}
|
||||
.note-ep{font-size:.72rem;color:rgba(255,255,255,.3)}
|
||||
.note-ts{font-size:.72rem;color:#ffd700;display:inline-flex;align-items:center;gap:4px}
|
||||
.note-date{font-size:.68rem;color:rgba(255,255,255,.25);margin-left:auto}
|
||||
.note-text{font-size:.87rem;color:rgba(255,255,255,.65);line-height:1.6}
|
||||
|
||||
/* ── Comments ─────────────────────────────────────────────────── */
|
||||
.cm-card{
|
||||
background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.07);
|
||||
border-radius:12px;padding:14px 16px;margin-bottom:10px;
|
||||
}
|
||||
.cm-top{display:flex;align-items:center;gap:10px;margin-bottom:10px}
|
||||
.cm-ava{width:30px;height:30px;border-radius:10px;background:linear-gradient(135deg,var(--accent2),var(--accent));display:flex;align-items:center;justify-content:center;font-size:.75rem;font-weight:800;color:#fff;flex-shrink:0}
|
||||
.cm-name{font-size:.84rem;font-weight:700;color:rgba(255,255,255,.8)}
|
||||
.cm-time{font-size:.72rem;color:rgba(255,255,255,.25);margin-left:auto}
|
||||
.cm-text{font-size:.88rem;color:rgba(255,255,255,.6);line-height:1.6}
|
||||
.cm-gif{max-width:200px;border-radius:8px;margin-top:8px}
|
||||
|
||||
.pr-empty{text-align:center;padding:56px 20px;color:rgba(255,255,255,.2);font-size:.9rem}
|
||||
.pr-empty i{font-size:2.5rem;display:block;margin-bottom:12px;opacity:.25}
|
||||
|
||||
/* ── Responsive ───────────────────────────────────────────────── */
|
||||
@media(max-width:600px){
|
||||
.pr-hero-inner{padding:calc(var(--nav-h) + 16px) 16px 0}
|
||||
.pr-body{padding:24px 16px 48px}
|
||||
.pr-avatar{width:72px;height:72px;border-radius:18px;font-size:1.8rem}
|
||||
.pr-name{font-size:1.3rem}
|
||||
.pr-stat{padding:8px 12px;min-width:60px}
|
||||
.pr-stat .v{font-size:1rem}
|
||||
.ach-grid{grid-template-columns:1fr}
|
||||
.cw-grid{grid-template-columns:repeat(auto-fill,minmax(110px,1fr))}
|
||||
.pr-top{flex-direction:column;gap:14px}
|
||||
.pr-top-main{align-items:flex-start}
|
||||
.pr-edit-btn{align-self:stretch;justify-content:center}
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════
|
||||
PROFILE PAGE PREMIUM ENHANCEMENTS
|
||||
═══════════════════════════════════════════════════ */
|
||||
|
||||
/* Avatar animated rainbow border */
|
||||
@keyframes avatar-border-spin{
|
||||
0%{background-position:0% 50%}
|
||||
100%{background-position:200% 50%}
|
||||
}
|
||||
.pr-avatar{
|
||||
position:relative;
|
||||
}
|
||||
.pr-avatar::before{
|
||||
content:'';position:absolute;inset:-2px;border-radius:26px;z-index:-1;
|
||||
background:linear-gradient(135deg,var(--accent2),var(--accent),var(--accent3),var(--accent2));
|
||||
background-size:300% 300%;
|
||||
animation:avatar-border-spin 3s linear infinite;
|
||||
}
|
||||
|
||||
/* Username gradient */
|
||||
.pr-name{
|
||||
background:linear-gradient(135deg,#fff 0%,rgba(255,255,255,.85) 60%,rgba(240,244,255,.6) 100%);
|
||||
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;
|
||||
}
|
||||
|
||||
/* Stats strip enhanced */
|
||||
.pr-stats{
|
||||
background:rgba(255,255,255,.02);
|
||||
border-radius:14px;
|
||||
padding:14px;
|
||||
border:1px solid rgba(255,255,255,.05);
|
||||
gap:8px;
|
||||
}
|
||||
.pr-stat{
|
||||
border-radius:10px;
|
||||
background:rgba(255,255,255,.04);
|
||||
border:1px solid rgba(255,255,255,.07);
|
||||
transition:all .2s;
|
||||
}
|
||||
.pr-stat:hover{
|
||||
background:rgba(0,245,255,.06);
|
||||
border-color:rgba(0,245,255,.2);
|
||||
transform:translateY(-2px);
|
||||
}
|
||||
.pr-stat .v{
|
||||
background:linear-gradient(135deg,var(--accent2),var(--accent));
|
||||
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;
|
||||
font-size:1.35rem;
|
||||
}
|
||||
|
||||
/* Tab enhanced */
|
||||
.pr-tab.on{
|
||||
color:var(--accent2);
|
||||
text-shadow:0 0 12px rgba(0,245,255,.3);
|
||||
}
|
||||
|
||||
/* Entrance animations */
|
||||
@keyframes pr-fade-up{
|
||||
from{opacity:0;transform:translateY(18px)}
|
||||
to{opacity:1;transform:none}
|
||||
}
|
||||
.pr-avatar{animation:pr-fade-up .5s cubic-bezier(.22,1,.36,1) .1s both}
|
||||
.pr-info{animation:pr-fade-up .5s cubic-bezier(.22,1,.36,1) .2s both}
|
||||
.pr-stats{animation:pr-fade-up .5s cubic-bezier(.22,1,.36,1) .3s both}
|
||||
.pr-tabs{animation:pr-fade-up .4s cubic-bezier(.22,1,.36,1) .4s both}
|
||||
|
||||
/* Achievement cards enhanced */
|
||||
.ach-card.earned{
|
||||
border:1px solid rgba(255,255,255,.1);
|
||||
background:linear-gradient(135deg,rgba(255,255,255,.05),rgba(0,245,255,.02));
|
||||
transition:all .2s;
|
||||
}
|
||||
.ach-card.earned:hover{
|
||||
border-color:rgba(0,245,255,.2);
|
||||
transform:translateY(-2px);
|
||||
box-shadow:0 8px 24px rgba(0,0,0,.4),0 0 20px rgba(0,245,255,.05);
|
||||
}
|
||||
|
||||
/* Watchlist cards enhanced */
|
||||
.wl-card:hover{
|
||||
transform:translateY(-3px);
|
||||
border-color:rgba(0,245,255,.2);
|
||||
box-shadow:0 8px 24px rgba(0,0,0,.4);
|
||||
}
|
||||
|
||||
/* Heatmap wrap */
|
||||
.heatmap-wrap{
|
||||
background:linear-gradient(135deg,rgba(255,255,255,.03),rgba(0,245,255,.01));
|
||||
border:1px solid rgba(0,245,255,.07);
|
||||
}
|
||||
|
||||
/* Profile edit button */
|
||||
.pr-edit-btn{
|
||||
transition:all .18s;
|
||||
}
|
||||
.pr-edit-btn:hover{
|
||||
background:rgba(0,245,255,.12);
|
||||
border-color:rgba(0,245,255,.4);
|
||||
color:var(--accent2);
|
||||
box-shadow:0 0 20px rgba(0,245,255,.15);
|
||||
}
|
||||
|
||||
/* Body panes reveal */
|
||||
.pr-body{animation:pr-fade-up .5s cubic-bezier(.22,1,.36,1) .2s both}
|
||||
|
||||
/* Profile color accent on section headers */
|
||||
.pr-sec-h::before{
|
||||
box-shadow:0 0 10px rgba(0,245,255,.5);
|
||||
}
|
||||
|
||||
/* ── Swipe history ───────────────────────────────────── */
|
||||
.swipe-filter {
|
||||
padding: 5px 13px; border-radius: 999px; font-size: .68rem;
|
||||
background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.08);
|
||||
color: var(--text3); cursor: pointer; font-family: var(--font);
|
||||
transition: all .15s; display: inline-flex; align-items: center; gap: 5px;
|
||||
}
|
||||
.swipe-filter:hover { border-color: rgba(0,245,255,.25); color: var(--text2); }
|
||||
.swipe-filter.on { background: rgba(0,245,255,.1); border-color: var(--accent2); color: var(--accent2); }
|
||||
.swipe-f-count {
|
||||
font-size: .6rem; background: rgba(255,255,255,.08); border-radius: 999px;
|
||||
padding: 1px 6px; color: var(--text3);
|
||||
}
|
||||
.swipe-filter.on .swipe-f-count { background: rgba(0,245,255,.15); color: var(--accent2); }
|
||||
|
||||
.swipe-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
.swipe-item {
|
||||
text-decoration: none; border-radius: 12px; overflow: hidden;
|
||||
background: var(--surface2); display: flex; flex-direction: column;
|
||||
transition: transform .18s, box-shadow .18s;
|
||||
}
|
||||
.swipe-item:hover { transform: translateY(-3px); box-shadow: 0 8px 24px rgba(0,0,0,.4); }
|
||||
.swipe-poster {
|
||||
position: relative; aspect-ratio: 2/3; overflow: hidden;
|
||||
}
|
||||
.swipe-poster img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
||||
.swipe-poster-ph {
|
||||
width: 100%; height: 100%;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
color: var(--text3); font-size: 1.5rem;
|
||||
}
|
||||
.swipe-dir-badge {
|
||||
position: absolute; top: 6px; right: 6px;
|
||||
width: 22px; height: 22px; border-radius: 50%;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: .6rem; font-weight: 700;
|
||||
}
|
||||
.badge-like { background: rgba(0,245,255,.18); color: var(--accent2); border: 1px solid rgba(0,245,255,.3); }
|
||||
.badge-skip { background: rgba(255,45,125,.15); color: #ff2d7d; border: 1px solid rgba(255,45,125,.3); }
|
||||
.swipe-info { padding: 7px 8px 9px; }
|
||||
.swipe-title {
|
||||
font-size: .68rem; font-weight: 600; color: var(--text);
|
||||
line-height: 1.3; margin-bottom: 4px;
|
||||
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
|
||||
}
|
||||
.swipe-meta { display: flex; gap: 6px; font-size: .6rem; color: var(--text3); flex-wrap: wrap; }
|
||||
.swipe-item.skip .swipe-poster { opacity: .65; }
|
||||
.swipe-item.skip .swipe-poster img { filter: grayscale(25%); }
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
|
||||
@php $pColor = $user->profile_color ?? '#00f5ff'; @endphp
|
||||
|
||||
{{-- Hero --}}
|
||||
<div class="pr-hero" style="--pr-color:{{ $pColor }}">
|
||||
|
||||
{{-- Banner --}}
|
||||
@if($user->banner_image)
|
||||
<div style="position:absolute;inset:0;overflow:hidden">
|
||||
<img src="{{ \App\Support\MediaUrl::fromStoragePath($user->banner_image) }}" alt=""
|
||||
style="width:100%;height:100%;object-fit:cover;opacity:.35;filter:blur(1px)">
|
||||
<div style="position:absolute;inset:0;background:linear-gradient(to bottom,rgba(5,5,14,.3) 0%,rgba(5,5,14,.85) 100%)"></div>
|
||||
</div>
|
||||
@else
|
||||
<div class="pr-hero-bg" style="background:radial-gradient(ellipse 80% 60% at 20% 50%,{{ $pColor }}18,transparent),radial-gradient(ellipse 60% 80% at 80% 30%,{{ $pColor }}10,transparent)"></div>
|
||||
@endif
|
||||
|
||||
<div class="pr-hero-inner">
|
||||
|
||||
{{-- Top row: avatar + info + edit button --}}
|
||||
<div class="pr-top">
|
||||
<div class="pr-top-main">
|
||||
{{-- Avatar --}}
|
||||
<div class="pr-avatar" style="background:linear-gradient(135deg,{{ $pColor }},{{ $pColor }}88);box-shadow:0 0 0 3px {{ $pColor }}33,0 16px 48px rgba(0,0,0,.5)">
|
||||
@if($user->avatar)
|
||||
<img src="{{ \App\Support\MediaUrl::fromStoragePath($user->avatar) }}" alt="{{ $user->name }}"
|
||||
style="width:100%;height:100%;object-fit:cover;border-radius:22px">
|
||||
@else
|
||||
{{ mb_strtoupper(mb_substr($user->name,0,1)) }}
|
||||
@endif
|
||||
</div>
|
||||
<div class="pr-info">
|
||||
<div class="pr-name">{{ $user->name }}</div>
|
||||
@if($user->username)
|
||||
<div class="pr-handle">@php echo '@' . e($user->username); @endphp</div>
|
||||
@endif
|
||||
@if($user->bio)
|
||||
<div style="font-size:.83rem;color:rgba(255,255,255,.55);margin-bottom:10px;max-width:500px;line-height:1.5">{{ $user->bio }}</div>
|
||||
@endif
|
||||
|
||||
{{-- Sosyal linkler --}}
|
||||
@if($user->twitter || $user->instagram || $user->discord || $user->website)
|
||||
<div style="display:flex;gap:10px;flex-wrap:wrap;margin-bottom:10px;align-items:center">
|
||||
@if($user->twitter)
|
||||
<a href="https://x.com/{{ $user->twitter }}" target="_blank" rel="noopener"
|
||||
style="color:rgba(255,255,255,.5);font-size:.82rem;text-decoration:none;display:flex;align-items:center;gap:4px;transition:color .2s"
|
||||
onmouseover="this.style.color='{{ $pColor }}'" onmouseout="this.style.color='rgba(255,255,255,.5)'">
|
||||
<i class="bi bi-twitter-x"></i> {{ $user->twitter }}
|
||||
</a>
|
||||
@endif
|
||||
@if($user->instagram)
|
||||
<a href="https://instagram.com/{{ $user->instagram }}" target="_blank" rel="noopener"
|
||||
style="color:rgba(255,255,255,.5);font-size:.82rem;text-decoration:none;display:flex;align-items:center;gap:4px;transition:color .2s"
|
||||
onmouseover="this.style.color='{{ $pColor }}'" onmouseout="this.style.color='rgba(255,255,255,.5)'">
|
||||
<i class="bi bi-instagram"></i> {{ $user->instagram }}
|
||||
</a>
|
||||
@endif
|
||||
@if($user->discord)
|
||||
<span style="color:rgba(255,255,255,.5);font-size:.82rem;display:flex;align-items:center;gap:4px">
|
||||
<i class="bi bi-discord"></i> {{ $user->discord }}
|
||||
</span>
|
||||
@endif
|
||||
@if($user->website)
|
||||
<a href="{{ $user->website }}" target="_blank" rel="noopener"
|
||||
style="color:rgba(255,255,255,.5);font-size:.82rem;text-decoration:none;display:flex;align-items:center;gap:4px;transition:color .2s"
|
||||
onmouseover="this.style.color='{{ $pColor }}'" onmouseout="this.style.color='rgba(255,255,255,.5)'">
|
||||
<i class="bi bi-globe2"></i> {{ parse_url($user->website, PHP_URL_HOST) }}
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="pr-badges">
|
||||
@if($user->role==='admin')
|
||||
<span class="pbadge pbadge-admin"><i class="bi bi-shield-fill"></i> Admin</span>
|
||||
@elseif($user->role==='moderator')
|
||||
<span class="pbadge pbadge-admin"><i class="bi bi-shield-half"></i> Moderatör</span>
|
||||
@endif
|
||||
@if($user->isPremium())
|
||||
<span class="pbadge pbadge-premium"><i class="bi bi-star-fill"></i> Premium</span>
|
||||
@else
|
||||
<span class="pbadge pbadge-member"><i class="bi bi-person-check"></i> Üye</span>
|
||||
@endif
|
||||
<span class="pbadge" style="background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);color:rgba(255,255,255,.35)"><i class="bi bi-calendar3"></i> {{ $user->created_at->format('Y') }}'den beri</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Ayarlar butonu — ayrı satırda, üstte sabit --}}
|
||||
<a href="{{ route('profile.settings') }}" class="pr-edit-btn"
|
||||
style="flex-shrink:0;padding:8px 16px;border-radius:10px;background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.12);color:rgba(255,255,255,.6);font-size:.82rem;text-decoration:none;display:flex;align-items:center;gap:7px;transition:all .2s;white-space:nowrap;align-self:flex-start;margin-top:4px"
|
||||
onmouseover="this.style.background='rgba(255,255,255,.12)';this.style.color='#fff'"
|
||||
onmouseout="this.style.background='rgba(255,255,255,.07)';this.style.color='rgba(255,255,255,.6)'">
|
||||
<i class="bi bi-pencil-square"></i> Profili Düzenle
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{{-- Stats --}}
|
||||
<div class="pr-stats">
|
||||
<div class="pr-stat">
|
||||
<span class="v">{{ $watchStats['episodes'] }}</span>
|
||||
<span class="l">Bölüm</span>
|
||||
</div>
|
||||
<div class="pr-stat">
|
||||
<span class="v">{{ $watchStats['hours'] }}</span>
|
||||
<span class="l">Saat</span>
|
||||
</div>
|
||||
<div class="pr-stat">
|
||||
<span class="v">{{ $watchStats['watchlist'] }}</span>
|
||||
<span class="l">Listede</span>
|
||||
</div>
|
||||
<div class="pr-stat">
|
||||
<span class="v">{{ $commentCount }}</span>
|
||||
<span class="l">Yorum</span>
|
||||
</div>
|
||||
@if($allAchievements->count())
|
||||
<div class="pr-stat">
|
||||
<span class="v">{{ $achievements->count() }}</span>
|
||||
<span class="l">Başarım</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Tab nav --}}
|
||||
<div class="pr-tabs" id="pr-tabs">
|
||||
@if($continueItems->count())
|
||||
<button class="pr-tab on" data-pane="continue"><i class="bi bi-play-circle"></i> Devam Et</button>
|
||||
@endif
|
||||
<button class="pr-tab {{ !$continueItems->count() ? 'on' : '' }}" data-pane="watchlist"><i class="bi bi-bookmark"></i> Listem</button>
|
||||
<button class="pr-tab" data-pane="activity"><i class="bi bi-graph-up"></i> Aktivite</button>
|
||||
@if($allAchievements->count())
|
||||
<button class="pr-tab" data-pane="achievements"><i class="bi bi-trophy"></i> Başarımlar</button>
|
||||
@endif
|
||||
<button class="pr-tab" data-pane="notes"><i class="bi bi-journal-text"></i> Notlar @if($episodeNotes->count())<span style="font-size:.68rem;background:rgba(0,245,255,.15);color:var(--accent2);border-radius:10px;padding:1px 6px;margin-left:2px">{{ $episodeNotes->count() }}</span>@endif</button>
|
||||
<button class="pr-tab" data-pane="comments"><i class="bi bi-chat-dots"></i> Yorumlar</button>
|
||||
<button class="pr-tab" data-pane="swipes"><i class="bi bi-hand-index-thumb"></i> Keşfet @if($swipeHistory->count())<span style="font-size:.65rem;background:rgba(0,245,255,.12);color:var(--accent2);border-radius:10px;padding:1px 6px;margin-left:2px">{{ $swipeHistory->count() }}</span>@endif</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Body --}}
|
||||
<div class="pr-body">
|
||||
|
||||
{{-- DEVAM ET --}}
|
||||
@if($continueItems->count())
|
||||
<div class="pr-pane on" id="pane-continue">
|
||||
<div class="pr-sec-h"><span>Kaldığın Yerden Devam Et</span></div>
|
||||
<div class="cw-grid">
|
||||
@foreach($continueItems as $cw)
|
||||
@php $anime = $cw->anime; @endphp
|
||||
@if(!$anime) @continue @endif
|
||||
<a href="{{ route('watch',[$anime->slug,$cw->season_number,$cw->episode_number]) }}" class="cw-card">
|
||||
<div class="cw-thumb">
|
||||
@if($anime->cover_image)
|
||||
<img src="{{ \App\Support\MediaUrl::fromStoragePath($anime->cover_image) }}" alt="">
|
||||
@else
|
||||
<div class="cw-thumb-ph"><i class="bi bi-image"></i></div>
|
||||
@endif
|
||||
<div class="cw-grad"></div>
|
||||
<div class="cw-play"><i class="bi bi-play-fill"></i></div>
|
||||
<div class="cw-progress">
|
||||
<div class="cw-prog-bar"><div class="cw-prog-fill" style="width:{{ $cw->percent_complete }}%"></div></div>
|
||||
</div>
|
||||
<div class="cw-ep">S{{ str_pad($cw->season_number,2,'0',STR_PAD_LEFT) }}E{{ str_pad($cw->episode_number,2,'0',STR_PAD_LEFT) }} · {{ $cw->percent_complete }}%</div>
|
||||
</div>
|
||||
<div class="cw-info"><div class="cw-info-title">{{ $anime->title }}</div></div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- İZLEME LİSTESİ --}}
|
||||
<div class="pr-pane {{ !$continueItems->count() ? 'on' : '' }}" id="pane-watchlist">
|
||||
<div class="pr-sec-h" style="display:flex;align-items:center;justify-content:space-between">
|
||||
<span>İzleme Listesi</span>
|
||||
@if(auth()->user()->hasPerk('watchlist_export'))
|
||||
<div style="display:flex;gap:6px">
|
||||
<a href="{{ route('watchlist.export', ['format'=>'csv']) }}" style="font-size:.72rem;color:rgba(0,245,255,.7);text-decoration:none;display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border:1px solid rgba(0,245,255,.2);border-radius:6px">
|
||||
<i class="bi bi-download"></i> CSV
|
||||
</a>
|
||||
<a href="{{ route('watchlist.export', ['format'=>'json']) }}" style="font-size:.72rem;color:rgba(0,245,255,.7);text-decoration:none;display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border:1px solid rgba(0,245,255,.2);border-radius:6px">
|
||||
<i class="bi bi-download"></i> JSON
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@if($watchlistItems->count())
|
||||
{{-- Filter buttons --}}
|
||||
<div class="wl-filter">
|
||||
<button class="wl-filter-btn on" data-wl="all">Tümü</button>
|
||||
@foreach(\App\Models\Watchlist::STATUSES as $status => $label)
|
||||
@if(isset($watchlistItems[$status]) && $watchlistItems[$status]->count())
|
||||
<button class="wl-filter-btn" data-wl="{{ $status }}">{{ $label }} <span style="opacity:.5">({{ $watchlistItems[$status]->count() }})</span></button>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
@foreach(\App\Models\Watchlist::STATUSES as $status => $label)
|
||||
@if(isset($watchlistItems[$status]) && $watchlistItems[$status]->count())
|
||||
<div class="wl-section wl-grid" data-wl="{{ $status }}" style="margin-bottom:24px">
|
||||
@foreach($watchlistItems[$status] as $wl)
|
||||
@if(!$wl->anime) @continue @endif
|
||||
<a href="{{ $wl->anime->detailUrl }}" class="wl-card">
|
||||
@if($wl->anime->cover_image)
|
||||
<img src="{{ \App\Support\MediaUrl::fromStoragePath($wl->anime->cover_image) }}" alt="" loading="lazy">
|
||||
@else
|
||||
<div class="wl-card-ph"><i class="bi bi-image"></i></div>
|
||||
@endif
|
||||
<div class="wl-card-title">{{ $wl->anime->title }}</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
@else
|
||||
<div class="pr-empty"><i class="bi bi-bookmark"></i>Liste henüz boş.</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- AKTİVİTE / HEATMAP --}}
|
||||
<div class="pr-pane" id="pane-activity">
|
||||
<div class="pr-sec-h"><span>İzleme Aktivitesi — Son 1 Yıl</span></div>
|
||||
@php
|
||||
$today = now()->startOfDay();
|
||||
$start = $today->copy()->subDays(364);
|
||||
$gridStart= $start->copy()->startOfWeek(\Carbon\Carbon::MONDAY);
|
||||
$weeks = [];
|
||||
$cur = $gridStart->copy();
|
||||
while ($cur->lte($today)) {
|
||||
$week = [];
|
||||
for ($d = 0; $d < 7; $d++) {
|
||||
$key = $cur->format('Y-m-d');
|
||||
$week[] = ['date'=>$key,'count'=>$heatmapRaw[$key]??0,'past'=>$cur->lte($today)&&$cur->gte($start)];
|
||||
$cur->addDay();
|
||||
}
|
||||
$weeks[] = $week;
|
||||
}
|
||||
$maxCount = !empty($heatmapRaw) ? max($heatmapRaw) : 1;
|
||||
$totalDays = collect($heatmapRaw)->filter()->count();
|
||||
$totalEpYear= array_sum($heatmapRaw);
|
||||
@endphp
|
||||
<div class="heatmap-wrap">
|
||||
<div class="heatmap-scroll">
|
||||
<div class="heatmap-grid">
|
||||
@foreach($weeks as $week)
|
||||
<div class="hm-col">
|
||||
@foreach($week as $cell)
|
||||
@php
|
||||
$alpha = 0;
|
||||
$bg = 'rgba(255,255,255,.05)';
|
||||
if ($cell['past'] && $cell['count'] > 0) {
|
||||
$intensity = min(1, $cell['count'] / max($maxCount,1));
|
||||
$alpha = 0.18 + $intensity * 0.82;
|
||||
$bg = "rgba(0,245,255,{$alpha})";
|
||||
} elseif (!$cell['past']) {
|
||||
$bg = 'transparent';
|
||||
}
|
||||
@endphp
|
||||
<div class="hm-cell" title="{{ $cell['past'] ? $cell['date'].': '.($cell['count']?$cell['count'].' bölüm':'boş') : '' }}"
|
||||
style="background:{{ $bg }}"></div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="heatmap-legend">
|
||||
<span>Az</span>
|
||||
<div class="heatmap-legend-cells">
|
||||
<div style="width:13px;height:13px;border-radius:3px;background:rgba(255,255,255,.05)"></div>
|
||||
<div style="width:13px;height:13px;border-radius:3px;background:rgba(0,245,255,.2)"></div>
|
||||
<div style="width:13px;height:13px;border-radius:3px;background:rgba(0,245,255,.45)"></div>
|
||||
<div style="width:13px;height:13px;border-radius:3px;background:rgba(0,245,255,.7)"></div>
|
||||
<div style="width:13px;height:13px;border-radius:3px;background:rgba(0,245,255,1)"></div>
|
||||
</div>
|
||||
<span>Çok</span>
|
||||
</div>
|
||||
<div class="heatmap-stats">
|
||||
<span><i class="bi bi-calendar3 me-1"></i>{{ $totalDays }} aktif gün</span>
|
||||
<span><i class="bi bi-play-circle me-1"></i>{{ $totalEpYear }} bölüm izlendi</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- BAŞARIMLAR --}}
|
||||
@if($allAchievements->count())
|
||||
<div class="pr-pane" id="pane-achievements">
|
||||
@php $earnedIds = $achievements->pluck('achievement_id')->toArray(); @endphp
|
||||
<div class="pr-sec-h"><span>Başarımlar <span style="opacity:.4;font-weight:400">{{ $achievements->count() }}/{{ $allAchievements->count() }}</span></span></div>
|
||||
<div class="ach-grid">
|
||||
@foreach($allAchievements->sortByDesc(fn($a)=>in_array($a->id,$earnedIds)) as $ach)
|
||||
@php $earned = in_array($ach->id, $earnedIds); @endphp
|
||||
<div class="ach-card {{ $earned ? 'earned' : '' }}" style="{{ $earned ? 'border-color:'.substr($ach->color,0,7).'33' : '' }}">
|
||||
<div class="ach-icon-wrap" style="background:{{ $earned ? substr($ach->color,0,7).'1a' : 'rgba(255,255,255,.04)' }}">
|
||||
<i class="bi {{ $ach->icon }}" style="color:{{ $earned ? $ach->color : 'rgba(255,255,255,.2)' }}"></i>
|
||||
</div>
|
||||
<div class="ach-body">
|
||||
<div class="ach-title">{{ $ach->title }}</div>
|
||||
<div class="ach-desc">{{ $ach->description }}</div>
|
||||
@if($earned)
|
||||
@php $ea = $achievements->firstWhere('achievement_id',$ach->id); @endphp
|
||||
<div class="ach-date" style="color:{{ $ach->color }}">{{ $ea?->earned_at?->format('d.m.Y') }}</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- NOTLAR --}}
|
||||
<div class="pr-pane" id="pane-notes">
|
||||
<div class="pr-sec-h"><span>Bölüm Notlarım</span></div>
|
||||
@forelse($episodeNotes as $note)
|
||||
<div class="note-card">
|
||||
<div class="note-meta">
|
||||
@if($note->anime)<a href="{{ $note->anime->detailUrl }}" class="note-anime">{{ $note->anime->title }}</a>@endif
|
||||
@if($note->episode)<span class="note-ep">{{ $note->episode->episode_number }}. Bölüm</span>@endif
|
||||
@if($note->timestamp_at)<span class="note-ts"><i class="bi bi-clock"></i> {{ $note->timestamp_label }}</span>@endif
|
||||
<span class="note-date">{{ $note->created_at->format('d.m.Y') }}</span>
|
||||
</div>
|
||||
<div class="note-text">{{ $note->content }}</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="pr-empty"><i class="bi bi-journal-text"></i>Henüz not almadın.<br><small style="font-size:.78rem;opacity:.6">İzlerken bölüm içindeki not ikonuna tıklayarak not alabilirsin.</small></div>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
{{-- YORUMLAR --}}
|
||||
{{-- ── Keşfet Geçmişi ──────────────────────────────────────── --}}
|
||||
<div class="pr-pane" id="pane-swipes">
|
||||
<div class="pr-sec-h" style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px">
|
||||
<span>Keşfet Geçmişi</span>
|
||||
@if($swipeHistory->count())
|
||||
<div style="display:flex;gap:14px;font-size:.68rem;color:var(--text3)">
|
||||
<span style="color:var(--accent2)">
|
||||
<i class="bi bi-heart-fill" style="margin-right:3px"></i>
|
||||
{{ $swipeHistory->where('direction','like')->count() }} beğeni
|
||||
</span>
|
||||
<span>
|
||||
<i class="bi bi-x-lg" style="margin-right:3px;color:#ff2d7d"></i>
|
||||
{{ $swipeHistory->where('direction','skip')->count() }} geç
|
||||
</span>
|
||||
<a href="{{ route('discover') }}" style="color:var(--accent2);text-decoration:none">
|
||||
<i class="bi bi-arrow-right" style="margin-right:3px"></i>Devam et
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if($swipeHistory->isEmpty())
|
||||
<div class="pr-empty">
|
||||
<i class="bi bi-hand-index-thumb"></i>
|
||||
Henüz hiç anime keşfetmedin. <a href="{{ route('discover') }}" style="color:var(--accent2);text-decoration:none">Hemen başla →</a>
|
||||
</div>
|
||||
@else
|
||||
|
||||
{{-- Filter buttons --}}
|
||||
<div style="display:flex;gap:6px;margin-bottom:16px;flex-wrap:wrap">
|
||||
<button class="swipe-filter on" data-f="all">Tümü <span class="swipe-f-count">{{ $swipeHistory->count() }}</span></button>
|
||||
<button class="swipe-filter" data-f="like"><i class="bi bi-heart-fill" style="color:var(--accent2);font-size:.75rem"></i> Beğendiklerim <span class="swipe-f-count">{{ $swipeHistory->where('direction','like')->count() }}</span></button>
|
||||
<button class="swipe-filter" data-f="skip"><i class="bi bi-x-lg" style="color:#ff2d7d;font-size:.75rem"></i> Geçtiklerim <span class="swipe-f-count">{{ $swipeHistory->where('direction','skip')->count() }}</span></button>
|
||||
</div>
|
||||
|
||||
<div class="swipe-grid" id="swipeGrid">
|
||||
@foreach($swipeHistory as $sw)
|
||||
@php $a = $sw->anime; @endphp
|
||||
<a href="{{ $a->detailUrl }}" class="swipe-item {{ $sw->direction }}" data-dir="{{ $sw->direction }}" title="{{ $a->title }}">
|
||||
<div class="swipe-poster">
|
||||
@if($a->coverUrl)
|
||||
<img src="{{ $a->coverUrl }}" alt="{{ $a->title }}" loading="lazy">
|
||||
@else
|
||||
<div class="swipe-poster-ph"><i class="bi bi-film"></i></div>
|
||||
@endif
|
||||
<div class="swipe-dir-badge {{ $sw->direction === 'like' ? 'badge-like' : 'badge-skip' }}">
|
||||
@if($sw->direction === 'like')
|
||||
<i class="bi bi-heart-fill"></i>
|
||||
@else
|
||||
<i class="bi bi-x-lg"></i>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="swipe-info">
|
||||
<div class="swipe-title">{{ $a->title }}</div>
|
||||
<div class="swipe-meta">
|
||||
@if($a->release_year)<span>{{ $a->release_year }}</span>@endif
|
||||
@if($a->rating)<span style="color:#fbbf24"><i class="bi bi-star-fill" style="font-size:.55rem"></i> {{ number_format($a->rating,1) }}</span>@endif
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="pr-pane" id="pane-comments">
|
||||
<div class="pr-sec-h"><span>Son Yorumlar</span></div>
|
||||
@if($recentComments->isEmpty())
|
||||
<div class="pr-empty"><i class="bi bi-chat-dots"></i>Henüz yorum yok.</div>
|
||||
@else
|
||||
@foreach($recentComments as $c)
|
||||
<div class="cm-card">
|
||||
<div class="cm-top">
|
||||
<div class="cm-ava">{{ mb_strtoupper(mb_substr($user->name,0,1)) }}</div>
|
||||
<span class="cm-name">{{ $user->name }}</span>
|
||||
<span class="cm-time">{{ $c->created_at->diffForHumans() }}</span>
|
||||
</div>
|
||||
@if($c->content)<div class="cm-text">{{ $c->content }}</div>@endif
|
||||
@if($c->gif_url)<img src="{{ $c->gif_url }}" alt="" class="cm-gif">@endif
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
@push('scripts')
|
||||
<script>
|
||||
// Tab switching
|
||||
document.querySelectorAll('.pr-tab').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
document.querySelectorAll('.pr-tab').forEach(t => t.classList.remove('on'));
|
||||
document.querySelectorAll('.pr-pane').forEach(p => p.classList.remove('on'));
|
||||
btn.classList.add('on');
|
||||
document.getElementById('pane-' + btn.dataset.pane)?.classList.add('on');
|
||||
});
|
||||
});
|
||||
|
||||
// Watchlist filter
|
||||
document.querySelectorAll('.wl-filter-btn').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
document.querySelectorAll('.wl-filter-btn').forEach(b => b.classList.remove('on'));
|
||||
btn.classList.add('on');
|
||||
const target = btn.dataset.wl;
|
||||
document.querySelectorAll('.wl-section').forEach(sec => {
|
||||
sec.style.display = (target === 'all' || sec.dataset.wl === target) ? 'grid' : 'none';
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Swipe history filter
|
||||
document.querySelectorAll('.swipe-filter').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
document.querySelectorAll('.swipe-filter').forEach(b => b.classList.remove('on'));
|
||||
btn.classList.add('on');
|
||||
const f = btn.dataset.f;
|
||||
document.querySelectorAll('#swipeGrid .swipe-item').forEach(item => {
|
||||
item.style.display = (f === 'all' || item.dataset.dir === f) ? '' : 'none';
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,529 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', $user->name . ' — Profil — Animexe')
|
||||
@section('meta_description', ($user->bio ? $user->bio . ' — ' : '') . $user->name . ' Animexe profili.')
|
||||
@push('styles')
|
||||
<style>
|
||||
.pub-hero{
|
||||
position:relative;overflow:hidden;background:#05050e;
|
||||
}
|
||||
.pub-hero-animated{
|
||||
background:linear-gradient(135deg,#05050e,#0a0520);
|
||||
}
|
||||
.pub-hero-bg{
|
||||
position:absolute;inset:0;
|
||||
background:
|
||||
radial-gradient(ellipse 80% 60% at 20% 50%,rgba(0,245,255,.06),transparent),
|
||||
radial-gradient(ellipse 60% 80% at 80% 30%,rgba(255,45,125,.05),transparent);
|
||||
}
|
||||
.pub-hero-inner{
|
||||
position:relative;z-index:1;max-width:900px;margin:0 auto;
|
||||
padding:calc(var(--nav-h) + 36px) 24px 0;
|
||||
}
|
||||
.pub-top{display:flex;align-items:flex-start;gap:20px;flex-wrap:wrap;margin-bottom:28px}
|
||||
.pub-top-main{display:flex;align-items:flex-end;gap:20px;flex:1;min-width:0}
|
||||
.pub-avatar{
|
||||
width:96px;height:96px;border-radius:24px;flex-shrink:0;
|
||||
background:linear-gradient(135deg,var(--accent2),var(--accent));
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
font-size:2.4rem;font-weight:900;color:#fff;overflow:hidden;
|
||||
box-shadow:0 0 0 3px rgba(0,245,255,.2),0 16px 48px rgba(0,0,0,.5);
|
||||
}
|
||||
.pub-info{flex:1;min-width:0;padding-bottom:4px}
|
||||
.pub-name{font-size:1.7rem;font-weight:900;color:#fff;line-height:1.1;margin-bottom:4px}
|
||||
.pub-handle{font-size:.84rem;color:rgba(255,255,255,.35);margin-bottom:10px}
|
||||
.pub-badges{display:flex;gap:7px;flex-wrap:wrap}
|
||||
.pbadge{padding:4px 12px;border-radius:20px;font-size:.7rem;font-weight:700;letter-spacing:.05em;display:inline-flex;align-items:center;gap:5px}
|
||||
.pbadge-admin{background:rgba(255,45,125,.15);border:1px solid rgba(255,45,125,.35);color:var(--accent)}
|
||||
.pbadge-premium{background:rgba(255,208,0,.12);border:1px solid rgba(255,208,0,.3);color:#ffd700}
|
||||
.pbadge-member{background:rgba(0,245,255,.07);border:1px solid rgba(0,245,255,.2);color:var(--accent2)}
|
||||
|
||||
.pub-stats{
|
||||
display:flex;gap:6px;flex-wrap:wrap;
|
||||
padding:20px 0 0;border-top:1px solid rgba(255,255,255,.06);margin-top:8px;
|
||||
}
|
||||
.pub-stat{
|
||||
display:flex;flex-direction:column;align-items:center;
|
||||
padding:10px 20px;border-radius:12px;
|
||||
background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.07);
|
||||
min-width:80px;flex:1;
|
||||
}
|
||||
.pub-stat .v{font-size:1.25rem;font-weight:800;color:#fff;line-height:1}
|
||||
.pub-stat .l{font-size:.62rem;text-transform:uppercase;letter-spacing:.1em;color:rgba(255,255,255,.35);margin-top:4px;font-weight:600}
|
||||
|
||||
.pub-actions{display:flex;gap:8px;flex-wrap:wrap;align-self:flex-start;flex-shrink:0}
|
||||
.pub-btn{
|
||||
padding:8px 16px;border-radius:10px;font-size:.82rem;font-weight:700;
|
||||
display:inline-flex;align-items:center;gap:7px;cursor:pointer;
|
||||
border:none;font-family:inherit;transition:all .2s;text-decoration:none;white-space:nowrap;
|
||||
}
|
||||
.pub-btn-follow{background:var(--accent2);color:#05050e}
|
||||
.pub-btn-follow:hover{background:#00d4de}
|
||||
.pub-btn-follow.following{background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.15);color:rgba(255,255,255,.6)}
|
||||
.pub-btn-follow.following:hover{background:rgba(255,80,80,.12);border-color:rgba(255,80,80,.3);color:#ff5050}
|
||||
.pub-btn-msg{background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.12);color:rgba(255,255,255,.6)}
|
||||
.pub-btn-msg:hover{background:rgba(255,255,255,.12);color:#fff}
|
||||
.pub-btn-edit{background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.12);color:rgba(255,255,255,.6)}
|
||||
.pub-btn-edit:hover{background:rgba(255,255,255,.12);color:#fff}
|
||||
|
||||
.pub-compat{
|
||||
display:flex;align-items:center;gap:10px;
|
||||
background:rgba(0,245,255,.06);border:1px solid rgba(0,245,255,.15);
|
||||
border-radius:12px;padding:10px 16px;margin-top:14px;
|
||||
}
|
||||
.pub-compat-bar{flex:1;height:6px;background:rgba(255,255,255,.08);border-radius:3px;overflow:hidden}
|
||||
.pub-compat-fill{height:100%;background:linear-gradient(90deg,var(--accent2),var(--accent));border-radius:3px;transition:width .8s ease}
|
||||
.pub-compat-label{font-size:.75rem;color:var(--accent2);font-weight:700;white-space:nowrap}
|
||||
|
||||
.pub-tabs{
|
||||
display:flex;gap:2px;border-top:1px solid rgba(255,255,255,.06);
|
||||
margin-top:20px;overflow-x:auto;scrollbar-width:none;
|
||||
}
|
||||
.pub-tabs::-webkit-scrollbar{display:none}
|
||||
.pub-tab{
|
||||
padding:12px 18px;background:none;border:none;
|
||||
border-bottom:2px solid transparent;
|
||||
color:rgba(255,255,255,.35);font-size:.82rem;font-weight:600;
|
||||
cursor:pointer;font-family:inherit;transition:all .15s;
|
||||
white-space:nowrap;flex-shrink:0;display:flex;align-items:center;gap:6px;
|
||||
margin-bottom:-1px;
|
||||
}
|
||||
.pub-tab:hover{color:rgba(255,255,255,.65)}
|
||||
.pub-tab.on{color:var(--accent2);border-bottom-color:var(--accent2)}
|
||||
|
||||
.pub-body{max-width:900px;margin:0 auto;padding:32px 24px 64px}
|
||||
.pub-pane{display:none}
|
||||
.pub-pane.on{display:block}
|
||||
|
||||
.pub-sec-h{
|
||||
font-size:.68rem;text-transform:uppercase;letter-spacing:.12em;
|
||||
color:rgba(255,255,255,.3);font-weight:700;
|
||||
margin-bottom:16px;display:flex;align-items:center;gap:8px;
|
||||
}
|
||||
.pub-sec-h::before{content:'';width:3px;height:14px;background:linear-gradient(180deg,var(--accent2),var(--accent));border-radius:2px}
|
||||
|
||||
.pub-wl-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:10px}
|
||||
.pub-wl-card{
|
||||
border-radius:9px;overflow:hidden;text-decoration:none;display:block;
|
||||
background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.07);
|
||||
transition:transform .15s,border-color .15s;
|
||||
}
|
||||
.pub-wl-card:hover{transform:translateY(-2px);border-color:rgba(255,255,255,.18)}
|
||||
.pub-wl-card img{width:100%;aspect-ratio:2/3;object-fit:cover;display:block}
|
||||
.pub-wl-card-ph{aspect-ratio:2/3;background:rgba(255,255,255,.04);display:flex;align-items:center;justify-content:center;color:rgba(255,255,255,.2)}
|
||||
.pub-wl-card-title{padding:7px 8px;font-size:.72rem;font-weight:600;color:rgba(255,255,255,.7);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||
|
||||
.pub-ach-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:10px}
|
||||
.pub-ach-card{
|
||||
display:flex;align-items:center;gap:14px;
|
||||
background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.07);
|
||||
border-radius:12px;padding:14px 16px;
|
||||
}
|
||||
.pub-ach-icon{width:44px;height:44px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:1.4rem;flex-shrink:0}
|
||||
.pub-ach-title{font-size:.85rem;font-weight:700;color:#fff;margin-bottom:2px}
|
||||
.pub-ach-desc{font-size:.72rem;color:rgba(255,255,255,.35);line-height:1.4}
|
||||
|
||||
.pub-comment-card{
|
||||
background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.07);
|
||||
border-radius:12px;padding:14px 16px;margin-bottom:10px;
|
||||
}
|
||||
.pub-cm-top{display:flex;align-items:center;gap:10px;margin-bottom:8px}
|
||||
.pub-cm-anime{font-size:.78rem;font-weight:600;color:var(--accent2);text-decoration:none}
|
||||
.pub-cm-anime:hover{text-decoration:underline}
|
||||
.pub-cm-time{font-size:.7rem;color:rgba(255,255,255,.25);margin-left:auto}
|
||||
.pub-cm-text{font-size:.87rem;color:rgba(255,255,255,.6);line-height:1.6}
|
||||
|
||||
.pub-empty{text-align:center;padding:48px 20px;color:rgba(255,255,255,.2);font-size:.9rem}
|
||||
.pub-empty i{font-size:2.5rem;display:block;margin-bottom:12px;opacity:.25}
|
||||
|
||||
@media(max-width:600px){
|
||||
.pub-hero-inner{padding:calc(var(--nav-h) + 16px) 16px 0}
|
||||
.pub-body{padding:24px 16px 48px}
|
||||
.pub-avatar{width:72px;height:72px;border-radius:18px;font-size:1.8rem}
|
||||
.pub-name{font-size:1.3rem}
|
||||
.pub-top{flex-direction:column;gap:14px}
|
||||
.pub-ach-grid{grid-template-columns:1fr}
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
@php
|
||||
$pColor = $user->profile_color ?? '#00f5ff';
|
||||
$profBg = ($user->profile_bg && $user->hasPerk('profile_bg')) ? $user->profile_bg : null;
|
||||
$animBanner = $user->hasPerk('animated_banner') && $user->animated_banner;
|
||||
$watchRank = $user->watchRank();
|
||||
$musicUrl = ($user->profile_music_url && $user->hasPerk('profile_music')) ? $user->profile_music_url : null;
|
||||
@endphp
|
||||
|
||||
<div class="pub-hero {{ $profBg ? 'profile-bg-'.$profBg : '' }} {{ $animBanner ? 'pub-hero-animated' : '' }}" style="--pr-color:{{ $pColor }}">
|
||||
@if($animBanner)
|
||||
<canvas id="banner-canvas" style="position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:0"></canvas>
|
||||
@endif
|
||||
@if($user->banner_image)
|
||||
<div style="position:absolute;inset:0;overflow:hidden;z-index:0">
|
||||
<img src="{{ \App\Support\MediaUrl::fromStoragePath($user->banner_image) }}" alt=""
|
||||
style="width:100%;height:100%;object-fit:cover;opacity:.35;filter:blur(1px)">
|
||||
<div style="position:absolute;inset:0;background:linear-gradient(to bottom,rgba(5,5,14,.3) 0%,rgba(5,5,14,.85) 100%)"></div>
|
||||
</div>
|
||||
@else
|
||||
<div class="pub-hero-bg" style="background:radial-gradient(ellipse 80% 60% at 20% 50%,{{ $pColor }}18,transparent),radial-gradient(ellipse 60% 80% at 80% 30%,{{ $pColor }}10,transparent)"></div>
|
||||
@endif
|
||||
|
||||
<div class="pub-hero-inner">
|
||||
<div class="pub-top">
|
||||
<div class="pub-top-main">
|
||||
@php
|
||||
$hasFrame = $user->profile_frame && $user->hasPerk('profile_frame');
|
||||
$avatarSrc = $user->gif_avatar && $user->hasPerk('gif_avatar')
|
||||
? $user->gif_avatar
|
||||
: ($user->avatar ? \App\Support\MediaUrl::fromStoragePath($user->avatar) : null);
|
||||
@endphp
|
||||
<div class="{{ $hasFrame ? 'avatar-wrap' : '' }}" style="{{ $hasFrame ? 'width:96px;height:96px' : '' }}">
|
||||
@if($hasFrame)
|
||||
<div class="avatar-frame frame-{{ $user->profile_frame }}"></div>
|
||||
@endif
|
||||
<div class="pub-avatar" style="{{ $hasFrame ? 'border-radius:50%;position:relative;z-index:3' : 'background:linear-gradient(135deg,'.$pColor.','.$pColor.'88);box-shadow:0 0 0 3px '.$pColor.'33,0 16px 48px rgba(0,0,0,.5)' }}">
|
||||
@if($avatarSrc)
|
||||
<img src="{{ $avatarSrc }}" alt="{{ $user->name }}"
|
||||
style="width:100%;height:100%;object-fit:cover;border-radius:inherit">
|
||||
@else
|
||||
{{ mb_strtoupper(mb_substr($user->name,0,1)) }}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="pub-info">
|
||||
@php
|
||||
$unColor = $user->username_color && $user->hasPerk('username_color') ? 'username-color-'.$user->username_color : '';
|
||||
$unEffect = $user->username_effect && $user->hasPerk('username_effect') ? 'username-effect-'.$user->username_effect : '';
|
||||
@endphp
|
||||
<div class="pub-name {{ $unColor }} {{ $unEffect }}"
|
||||
@if($user->username_effect==='glitch' && $unEffect) data-text="{{ $user->name }}" @endif>{{ $user->name }}</div>
|
||||
@if($user->username)
|
||||
<div class="pub-handle">@php echo '@' . e($user->username); @endphp</div>
|
||||
@endif
|
||||
@if($user->bio)
|
||||
<div style="font-size:.83rem;color:rgba(255,255,255,.55);margin-bottom:10px;max-width:500px;line-height:1.5">{{ $user->bio }}</div>
|
||||
@endif
|
||||
<div class="pub-badges">
|
||||
@if($user->role==='admin')
|
||||
<span class="pbadge pbadge-admin"><i class="bi bi-shield-fill"></i> Admin</span>
|
||||
@elseif($user->role==='moderator')
|
||||
<span class="pbadge pbadge-admin"><i class="bi bi-shield-half"></i> Moderatör</span>
|
||||
@endif
|
||||
@if($user->isPremium())
|
||||
<span class="pbadge pbadge-premium"><i class="bi bi-star-fill"></i> Premium</span>
|
||||
@else
|
||||
<span class="pbadge pbadge-member"><i class="bi bi-person-check"></i> Üye</span>
|
||||
@endif
|
||||
@if($user->profile_badge && $user->hasPerk('profile_badge'))
|
||||
<span class="premium-badge user-badge-custom">{{ $user->profile_badge }}</span>
|
||||
@endif
|
||||
@if($watchRank)
|
||||
<span class="pbadge" style="background:rgba(255,255,255,.06);border:1px solid {{ $watchRank['color'] }}44;color:{{ $watchRank['color'] }}">
|
||||
<i class="bi {{ $watchRank['icon'] }}"></i> {{ $watchRank['label'] }}
|
||||
</span>
|
||||
@endif
|
||||
<span class="pbadge" style="background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);color:rgba(255,255,255,.35)"><i class="bi bi-calendar3"></i> {{ $user->created_at->format('Y') }}'den beri</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pub-actions">
|
||||
@if($isOwnProfile)
|
||||
<a href="{{ route('profile.settings') }}" class="pub-btn pub-btn-edit">
|
||||
<i class="bi bi-pencil-square"></i> Profili Düzenle
|
||||
</a>
|
||||
@elseif(auth()->check())
|
||||
<button id="follow-btn" onclick="toggleFollow()"
|
||||
class="pub-btn pub-btn-follow {{ $isFollowing ? 'following' : '' }}"
|
||||
data-following="{{ $isFollowing ? '1' : '0' }}">
|
||||
<i class="bi {{ $isFollowing ? 'bi-person-check-fill' : 'bi-person-plus' }}" id="follow-icon"></i>
|
||||
<span id="follow-label">{{ $isFollowing ? 'Takip Ediliyor' : 'Takip Et' }}</span>
|
||||
</button>
|
||||
<form method="POST" action="{{ route('messages.start', $user) }}">
|
||||
@csrf
|
||||
<button type="submit" class="pub-btn pub-btn-msg">
|
||||
<i class="bi bi-chat-dots"></i> Mesaj
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($compatibility !== null)
|
||||
<div class="pub-compat">
|
||||
<i class="bi bi-heart-pulse" style="color:var(--accent2);font-size:1rem;flex-shrink:0"></i>
|
||||
<div style="flex:1;min-width:0">
|
||||
<div style="font-size:.72rem;color:rgba(255,255,255,.4);margin-bottom:5px">Anime zevk uyumu</div>
|
||||
<div class="pub-compat-bar"><div class="pub-compat-fill" id="compat-fill" style="width:0%"></div></div>
|
||||
</div>
|
||||
<span class="pub-compat-label" id="compat-pct">%{{ $compatibility }}</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="pub-stats">
|
||||
<div class="pub-stat"><span class="v">{{ $watchStats['episodes'] }}</span><span class="l">Bölüm</span></div>
|
||||
<div class="pub-stat"><span class="v">{{ $watchStats['hours'] }}</span><span class="l">Saat</span></div>
|
||||
<div class="pub-stat"><span class="v" id="follower-count">{{ $followerCount }}</span><span class="l">Takipçi</span></div>
|
||||
<div class="pub-stat"><span class="v">{{ $followingCount }}</span><span class="l">Takip</span></div>
|
||||
<div class="pub-stat"><span class="v">{{ $commentCount }}</span><span class="l">Yorum</span></div>
|
||||
</div>
|
||||
|
||||
<div class="pub-tabs">
|
||||
<button class="pub-tab on" onclick="switchTab('watchlist',this)"><i class="bi bi-bookmark"></i> İzleme Listesi</button>
|
||||
<button class="pub-tab" onclick="switchTab('achievements',this)"><i class="bi bi-trophy"></i> Başarımlar</button>
|
||||
<button class="pub-tab" onclick="switchTab('comments',this)"><i class="bi bi-chat-dots"></i> Yorumlar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($musicUrl)
|
||||
<div id="profile-music-bar" style="
|
||||
position:fixed;bottom:0;left:0;right:0;z-index:900;
|
||||
background:rgba(5,5,14,.92);backdrop-filter:blur(12px);
|
||||
border-top:1px solid rgba(0,245,255,.15);
|
||||
display:flex;align-items:center;gap:12px;padding:10px 20px;
|
||||
font-size:.82rem;
|
||||
">
|
||||
<button id="music-toggle" onclick="toggleMusic()" style="
|
||||
background:rgba(0,245,255,.12);border:1px solid rgba(0,245,255,.3);color:#00f5ff;
|
||||
border-radius:50%;width:36px;height:36px;display:flex;align-items:center;justify-content:center;
|
||||
cursor:pointer;flex-shrink:0;font-size:1rem;
|
||||
"><i class="bi bi-play-fill" id="music-icon"></i></button>
|
||||
<div style="flex:1;min-width:0">
|
||||
<div style="color:rgba(255,255,255,.5);font-size:.7rem;margin-bottom:2px">{{ $user->name }} · Profil Müziği</div>
|
||||
<div id="music-progress-bar" style="width:100%;height:3px;background:rgba(255,255,255,.1);border-radius:2px;overflow:hidden">
|
||||
<div id="music-progress-fill" style="width:0%;height:100%;background:linear-gradient(90deg,#00f5ff,#b84dff);transition:width .5s linear;border-radius:2px"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button onclick="document.getElementById('profile-music-bar').remove()" style="
|
||||
background:none;border:none;color:rgba(255,255,255,.3);cursor:pointer;font-size:1.1rem;padding:4px;
|
||||
"><i class="bi bi-x"></i></button>
|
||||
<audio id="profile-audio" src="" preload="none"></audio>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="pub-body">
|
||||
|
||||
{{-- İzleme Listesi --}}
|
||||
<div class="pub-pane on" id="pane-watchlist">
|
||||
@php $watching = $watchlistItems->get('watching',[]);
|
||||
$completed = $watchlistItems->get('completed',[]);
|
||||
$planToWatch = $watchlistItems->get('plan_to_watch',[]); @endphp
|
||||
|
||||
@if($watchlistItems->isEmpty())
|
||||
<div class="pub-empty"><i class="bi bi-bookmark"></i> Henüz izleme listesi yok.</div>
|
||||
@else
|
||||
@foreach(['watching'=>'İzliyor','completed'=>'Tamamladı','plan_to_watch'=>'İzleyecek'] as $status => $label)
|
||||
@php $items = $watchlistItems->get($status, collect()); @endphp
|
||||
@if($items->count())
|
||||
<div class="pub-sec-h">{{ $label }} <span style="color:rgba(255,255,255,.2)">({{ $items->count() }})</span></div>
|
||||
<div class="pub-wl-grid" style="margin-bottom:28px">
|
||||
@foreach($items->take(12) as $wl)
|
||||
@if($wl->anime)
|
||||
<a href="{{ $wl->anime->detailUrl }}" class="pub-wl-card">
|
||||
@if($wl->anime->cover_image)
|
||||
<img src="{{ \App\Support\MediaUrl::fromStoragePath($wl->anime->cover_image) }}" alt="{{ $wl->anime->title }}" loading="lazy">
|
||||
@else
|
||||
<div class="pub-wl-card-ph"><i class="bi bi-image"></i></div>
|
||||
@endif
|
||||
<div class="pub-wl-card-title">{{ $wl->anime->title }}</div>
|
||||
</a>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Başarımlar --}}
|
||||
<div class="pub-pane" id="pane-achievements">
|
||||
@if($achievements->isEmpty())
|
||||
<div class="pub-empty"><i class="bi bi-trophy"></i> Henüz başarım kazanılmamış.</div>
|
||||
@else
|
||||
<div class="pub-ach-grid">
|
||||
@foreach($achievements as $ua)
|
||||
<div class="pub-ach-card">
|
||||
<div class="pub-ach-icon" style="background:{{ substr($ua->achievement->color ?? '#ffffff',0,7) }}22">
|
||||
<i class="bi {{ $ua->achievement->icon ?? 'bi-trophy' }}" style="color:{{ $ua->achievement->color ?? '#ffffff' }}"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="pub-ach-title">{{ $ua->achievement->name }}</div>
|
||||
<div class="pub-ach-desc">{{ $ua->achievement->description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Yorumlar --}}
|
||||
<div class="pub-pane" id="pane-comments">
|
||||
@if($recentComments->isEmpty())
|
||||
<div class="pub-empty"><i class="bi bi-chat-dots"></i> Henüz yorum yok.</div>
|
||||
@else
|
||||
@foreach($recentComments as $c)
|
||||
@php $ep = $c->episode; $anime = $ep?->anime ?? $c->anime; @endphp
|
||||
<div class="pub-comment-card">
|
||||
<div class="pub-cm-top">
|
||||
@if($anime)
|
||||
<a href="{{ $anime->detailUrl }}" class="pub-cm-anime"><i class="bi bi-play-circle"></i> {{ $anime->title }}</a>
|
||||
@endif
|
||||
<span class="pub-cm-time">{{ $c->created_at->diffForHumans() }}</span>
|
||||
</div>
|
||||
<div class="pub-cm-text">{{ Str::limit($c->content, 200) }}</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
function switchTab(name, btn) {
|
||||
document.querySelectorAll('.pub-pane').forEach(p => p.classList.remove('on'));
|
||||
document.querySelectorAll('.pub-tab').forEach(t => t.classList.remove('on'));
|
||||
document.getElementById('pane-' + name).classList.add('on');
|
||||
btn.classList.add('on');
|
||||
}
|
||||
|
||||
// Uyum barı animasyonu
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const fill = document.getElementById('compat-fill');
|
||||
if (fill) setTimeout(() => fill.style.width = '{{ $compatibility ?? 0 }}%', 300);
|
||||
});
|
||||
|
||||
// ── Animasyonlu Banner ────────────────────────────────────────────────────
|
||||
@if($animBanner)
|
||||
(function(){
|
||||
const canvas = document.getElementById('banner-canvas');
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext('2d');
|
||||
const color = '{{ $pColor }}';
|
||||
let W, H, particles = [];
|
||||
function resize(){
|
||||
W = canvas.width = canvas.offsetWidth;
|
||||
H = canvas.height = canvas.offsetHeight;
|
||||
}
|
||||
resize();
|
||||
window.addEventListener('resize', resize);
|
||||
for (let i = 0; i < 55; i++) {
|
||||
particles.push({
|
||||
x: Math.random()*1000, y: Math.random()*300,
|
||||
r: Math.random()*2+.5, vx: (Math.random()-.5)*.4,
|
||||
vy: (Math.random()-.5)*.4, a: Math.random()*.6+.1
|
||||
});
|
||||
}
|
||||
function hex2rgb(h){ const r=parseInt(h.slice(1,3),16),g=parseInt(h.slice(3,5),16),b=parseInt(h.slice(5,7),16); return `${r},${g},${b}`; }
|
||||
const rgb = hex2rgb(color.length===7 ? color : '#00f5ff');
|
||||
function draw(){
|
||||
ctx.clearRect(0,0,W,H);
|
||||
particles.forEach(p => {
|
||||
p.x += p.vx; p.y += p.vy;
|
||||
if (p.x<0) p.x=W; if (p.x>W) p.x=0;
|
||||
if (p.y<0) p.y=H; if (p.y>H) p.y=0;
|
||||
ctx.beginPath();
|
||||
ctx.arc(p.x,p.y,p.r,0,Math.PI*2);
|
||||
ctx.fillStyle = `rgba(${rgb},${p.a})`;
|
||||
ctx.fill();
|
||||
});
|
||||
// connecting lines
|
||||
particles.forEach((a,i) => {
|
||||
particles.slice(i+1).forEach(b => {
|
||||
const d = Math.hypot(a.x-b.x,a.y-b.y);
|
||||
if (d < 90) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(a.x,a.y); ctx.lineTo(b.x,b.y);
|
||||
ctx.strokeStyle = `rgba(${rgb},${(1-d/90)*.12})`;
|
||||
ctx.lineWidth = .6;
|
||||
ctx.stroke();
|
||||
}
|
||||
});
|
||||
});
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
draw();
|
||||
})();
|
||||
@endif
|
||||
|
||||
// ── Profil Müziği ─────────────────────────────────────────────────────────
|
||||
@if($musicUrl)
|
||||
(function(){
|
||||
const audio = document.getElementById('profile-audio');
|
||||
const icon = document.getElementById('music-icon');
|
||||
const fill = document.getElementById('music-progress-fill');
|
||||
if (!audio) return;
|
||||
|
||||
const src = {{ json_encode($musicUrl) }};
|
||||
// YouTube/SoundCloud embedding via iframe is complex; for direct audio URLs autoplay
|
||||
if (src.match(/\.(mp3|ogg|wav|m4a|aac|flac)(\?|$)/i)) {
|
||||
audio.src = src;
|
||||
audio.volume = 0.5;
|
||||
} else {
|
||||
// Not a direct audio file — show the bar with a link instead
|
||||
const bar = document.getElementById('profile-music-bar');
|
||||
if (bar) {
|
||||
const btn = document.getElementById('music-toggle');
|
||||
btn.innerHTML = '<i class="bi bi-box-arrow-up-right"></i>';
|
||||
btn.onclick = () => window.open(src, '_blank');
|
||||
fill.style.width = '100%';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
audio.addEventListener('timeupdate', () => {
|
||||
if (audio.duration) fill.style.width = (audio.currentTime/audio.duration*100)+'%';
|
||||
});
|
||||
audio.addEventListener('ended', () => {
|
||||
icon.className = 'bi bi-play-fill';
|
||||
fill.style.width = '0%';
|
||||
});
|
||||
|
||||
window.toggleMusic = function(){
|
||||
if (audio.paused) { audio.play(); icon.className = 'bi bi-pause-fill'; }
|
||||
else { audio.pause(); icon.className = 'bi bi-play-fill'; }
|
||||
};
|
||||
})();
|
||||
@else
|
||||
window.toggleMusic = function(){};
|
||||
@endif
|
||||
|
||||
// Takip toggle
|
||||
const FOLLOW_URL = '{{ route("user.follow", $user) }}';
|
||||
const CSRF = document.querySelector('meta[name=csrf-token]')?.content || '';
|
||||
|
||||
async function toggleFollow() {
|
||||
const btn = document.getElementById('follow-btn');
|
||||
if (!btn || btn.disabled) return;
|
||||
btn.disabled = true;
|
||||
|
||||
try {
|
||||
const res = await fetch(FOLLOW_URL, {
|
||||
method: 'POST',
|
||||
headers: { 'X-CSRF-TOKEN': CSRF, 'Accept': 'application/json' }
|
||||
});
|
||||
const d = await res.json();
|
||||
|
||||
const icon = document.getElementById('follow-icon');
|
||||
const label = document.getElementById('follow-label');
|
||||
const cnt = document.getElementById('follower-count');
|
||||
|
||||
if (d.following) {
|
||||
btn.classList.add('following');
|
||||
icon.className = 'bi bi-person-check-fill';
|
||||
label.textContent = 'Takip Ediliyor';
|
||||
} else {
|
||||
btn.classList.remove('following');
|
||||
icon.className = 'bi bi-person-plus';
|
||||
label.textContent = 'Takip Et';
|
||||
}
|
||||
if (cnt) cnt.textContent = d.followers_count;
|
||||
} catch(e) {}
|
||||
|
||||
btn.disabled = false;
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,229 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', ($q ? '"'.$q.'" — Arama' : 'Tüm Animeler') . ' — Animexe')
|
||||
@section('meta_description', $q ? '"' . $q . '" için anime arama sonuçları — Animexe\'de Türkçe anime izleyin.' : 'Animexe\'de tüm anime dizi ve filmlerini keşfedin. Tür, durum ve yıla göre filtreleyin.')
|
||||
@section('robots', ($q || request()->has('genre') || request()->has('type') || request()->has('year') || $results->currentPage() > 1) ? 'noindex, follow' : 'index, follow')
|
||||
@push('styles')
|
||||
<style>
|
||||
/* ═══════════════════════════════════════════════════
|
||||
SEARCH PAGE PREMIUM
|
||||
═══════════════════════════════════════════════════ */
|
||||
.srch-hero{
|
||||
background:linear-gradient(180deg,rgba(8,8,20,.98) 0%,rgba(6,6,13,.99) 100%);
|
||||
padding:clamp(28px,5vw,48px) clamp(16px,4vw,48px) clamp(24px,3.5vw,36px);
|
||||
border-bottom:1px solid rgba(0,245,255,.1);
|
||||
position:relative;overflow:hidden;
|
||||
}
|
||||
.srch-hero::before{
|
||||
content:'';position:absolute;top:-60%;left:-10%;right:-10%;bottom:-20%;
|
||||
background:
|
||||
radial-gradient(ellipse 60% 50% at 30% 50%,rgba(0,245,255,.05),transparent),
|
||||
radial-gradient(ellipse 50% 40% at 70% 50%,rgba(255,45,125,.04),transparent);
|
||||
pointer-events:none;
|
||||
}
|
||||
.srch-hero::after{
|
||||
content:'';position:absolute;bottom:0;left:5%;right:5%;height:1px;
|
||||
background:linear-gradient(90deg,transparent,var(--accent2),var(--accent),transparent);
|
||||
opacity:.4;
|
||||
}
|
||||
.srch-hero h1{
|
||||
font-family:var(--font-display);
|
||||
font-size:clamp(1.3rem,3vw,2rem);
|
||||
font-weight:900;margin-bottom:22px;letter-spacing:.05em;text-transform:uppercase;
|
||||
background:linear-gradient(135deg,#fff 0%,var(--accent2) 55%,var(--accent) 100%);
|
||||
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;
|
||||
animation:srch-in .5s cubic-bezier(.22,1,.36,1) both;
|
||||
}
|
||||
@keyframes srch-in{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
|
||||
.srch-form{
|
||||
display:flex;flex-direction:column;gap:10px;max-width:1100px;
|
||||
animation:srch-in .5s cubic-bezier(.22,1,.36,1) .1s both;
|
||||
}
|
||||
.srch-row{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
|
||||
.srch-inp-wrap{position:relative;flex:1 1 260px;min-width:0}
|
||||
.srch-inp-wrap i{position:absolute;left:13px;top:50%;transform:translateY(-50%);color:var(--accent2);font-size:.9rem;pointer-events:none;opacity:.8}
|
||||
.srch-inp-wrap input{
|
||||
width:100%;padding:13px 16px 13px 44px;
|
||||
background:rgba(17,17,31,.92);border:1px solid rgba(0,245,255,.22);
|
||||
border-radius:12px;color:var(--text);font-size:.94rem;outline:none;
|
||||
transition:border .18s,box-shadow .18s,background .18s;
|
||||
}
|
||||
.srch-inp-wrap input:focus{
|
||||
border-color:var(--accent2);
|
||||
box-shadow:0 0 0 3px rgba(0,245,255,.14),0 0 28px rgba(0,245,255,.08);
|
||||
background:rgba(0,245,255,.05);
|
||||
}
|
||||
.srch-inp-wrap input::placeholder{color:var(--text3)}
|
||||
.srch-sel{
|
||||
padding:11px 10px;
|
||||
background:#11111f;border:1px solid rgba(0,245,255,.15);
|
||||
border-radius:10px;color:var(--text);font-size:.82rem;outline:none;cursor:pointer;
|
||||
flex:1 1 120px;transition:border .18s;
|
||||
-webkit-appearance:none;appearance:none;
|
||||
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%2300f5ff' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
|
||||
background-repeat:no-repeat;
|
||||
background-position:right 10px center;
|
||||
padding-right:30px;
|
||||
}
|
||||
.srch-sel option{background:#11111f;color:var(--text)}
|
||||
.srch-sel:focus{border-color:var(--accent2);box-shadow:0 0 0 2px rgba(0,245,255,.1)}
|
||||
.srch-sel-sort{
|
||||
border-color:rgba(255,45,125,.4);
|
||||
background:#1a0d14;
|
||||
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23ff2d7d' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
|
||||
background-repeat:no-repeat;
|
||||
background-position:right 10px center;
|
||||
font-weight:700;
|
||||
color:#ff8ab0;
|
||||
}
|
||||
.srch-sel-sort option{background:#1a0d14;color:#fff}
|
||||
.srch-sel-sort:focus{border-color:var(--accent3)}
|
||||
.srch-btn{
|
||||
padding:11px 22px;border-radius:10px;border:none;
|
||||
background:linear-gradient(135deg,var(--accent),var(--accent3));
|
||||
color:#fff;font-size:.88rem;font-weight:800;cursor:pointer;
|
||||
transition:transform .14s,box-shadow .18s;flex-shrink:0;
|
||||
box-shadow:0 0 24px rgba(255,45,125,.3),0 4px 16px rgba(0,0,0,.3);
|
||||
}
|
||||
.srch-btn:hover{transform:translateY(-1px);box-shadow:0 0 32px rgba(255,45,125,.45);opacity:1}
|
||||
.srch-sort-label{
|
||||
font-size:.72rem;font-weight:700;color:var(--text3);letter-spacing:.06em;
|
||||
text-transform:uppercase;white-space:nowrap;padding-left:2px;
|
||||
}
|
||||
.srch-count{
|
||||
color:var(--text2);font-size:.85rem;margin-bottom:16px;
|
||||
animation:srch-in .4s cubic-bezier(.22,1,.36,1) .15s both;
|
||||
}
|
||||
.srch-count strong{color:var(--accent2)}
|
||||
|
||||
/* Card grid reveal animation */
|
||||
.a-grid .a-card{
|
||||
animation:srch-card-in .45s cubic-bezier(.22,1,.36,1) both;
|
||||
}
|
||||
@keyframes srch-card-in{
|
||||
from{opacity:0;transform:translateY(16px) scale(.97)}
|
||||
to{opacity:1;transform:none}
|
||||
}
|
||||
|
||||
@media(max-width:600px){
|
||||
.srch-hero{padding:24px 14px 20px}
|
||||
.srch-hero h1{font-size:1.05rem;margin-bottom:12px}
|
||||
.srch-form{gap:8px}
|
||||
.srch-sel{font-size:.8rem;padding:9px 8px;flex:1 1 90px}
|
||||
.srch-btn{width:100%;justify-content:center;padding:11px;display:flex;align-items:center;gap:6px}
|
||||
.srch-sort-label{display:none}
|
||||
}
|
||||
@media(max-width:380px){
|
||||
.srch-sel{flex:1 1 70px;font-size:.75rem;padding:8px 5px}
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="srch-hero">
|
||||
<div style="max-width:1600px;margin:0 auto">
|
||||
<h1>{{ $q ? '"'.$q.'" için sonuçlar' : 'Tüm Animeler' }}</h1>
|
||||
<form action="{{ route('search') }}" method="GET" class="srch-form">
|
||||
{{-- Satır 1: Arama kutusu + Ara butonu --}}
|
||||
<div class="srch-row">
|
||||
<div class="srch-inp-wrap">
|
||||
<i class="bi bi-search"></i>
|
||||
<input type="text" name="q" value="{{ $q }}" placeholder="Anime adı, alternatif isim...">
|
||||
</div>
|
||||
<button type="submit" class="srch-btn"><i class="bi bi-search"></i> Ara</button>
|
||||
</div>
|
||||
{{-- Satır 2: Filtreler + Sıralama --}}
|
||||
<div class="srch-row">
|
||||
<select name="type" class="srch-sel">
|
||||
<option value="">Format (Hepsi)</option>
|
||||
<option value="series" {{ $type==='series' ?'selected':'' }}>Dizi</option>
|
||||
<option value="movie" {{ $type==='movie' ?'selected':'' }}>Film</option>
|
||||
<option value="ova" {{ $type==='ova' ?'selected':'' }}>OVA</option>
|
||||
<option value="ona" {{ $type==='ona' ?'selected':'' }}>ONA</option>
|
||||
<option value="special" {{ $type==='special'?'selected':'' }}>Special</option>
|
||||
</select>
|
||||
<select name="status" class="srch-sel">
|
||||
<option value="">Durum (Hepsi)</option>
|
||||
<option value="ongoing" {{ $status==='ongoing' ?'selected':'' }}>Devam Ediyor</option>
|
||||
<option value="completed"{{ $status==='completed'?'selected':'' }}>Tamamlandı</option>
|
||||
<option value="upcoming" {{ $status==='upcoming' ?'selected':'' }}>Yakında</option>
|
||||
</select>
|
||||
<select name="genre" class="srch-sel">
|
||||
<option value="">Tür (Hepsi)</option>
|
||||
@foreach($genres as $g)
|
||||
<option value="{{ $g->slug }}" {{ $genre===$g->slug?'selected':'' }}>{{ $g->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<select name="year" class="srch-sel">
|
||||
<option value="">Yıl (Hepsi)</option>
|
||||
@foreach($years as $y)
|
||||
<option value="{{ $y }}" {{ (string)$year===(string)$y?'selected':'' }}>{{ $y }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<span class="srch-sort-label"><i class="bi bi-sort-down"></i> Sırala:</span>
|
||||
<select name="sort" class="srch-sel srch-sel-sort" onchange="this.form.submit()">
|
||||
<option value="popular" {{ $sort==='popular' ?'selected':'' }}>🔥 En Popüler</option>
|
||||
<option value="rating" {{ $sort==='rating' ?'selected':'' }}>⭐ En Yüksek Puan</option>
|
||||
<option value="newest" {{ $sort==='newest' ?'selected':'' }}>🆕 En Yeni</option>
|
||||
<option value="oldest" {{ $sort==='oldest' ?'selected':'' }}>📅 En Eski</option>
|
||||
<option value="az" {{ $sort==='az' ?'selected':'' }}>🔤 A → Z</option>
|
||||
<option value="za" {{ $sort==='za' ?'selected':'' }}>🔤 Z → A</option>
|
||||
@auth
|
||||
<option value="personalized" {{ $sort==='personalized' ?'selected':'' }}>✨ Sana Özel</option>
|
||||
@endauth
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
@php
|
||||
$sortLabels = [
|
||||
'popular' => '🔥 En Popüler',
|
||||
'rating' => '⭐ En Yüksek Puan',
|
||||
'newest' => '🆕 En Yeni',
|
||||
'oldest' => '📅 En Eski',
|
||||
'az' => '🔤 A → Z',
|
||||
'za' => '🔤 Z → A',
|
||||
'personalized'=> '✨ Sana Özel',
|
||||
];
|
||||
@endphp
|
||||
<p class="srch-count">
|
||||
Toplam <strong>{{ $results->total() }}</strong> anime bulundu
|
||||
<span style="margin-left:10px;font-size:.78rem;color:var(--text3)">· {{ $sortLabels[$sort] ?? '' }}</span>
|
||||
</p>
|
||||
|
||||
@if($results->count())
|
||||
<div class="a-grid">
|
||||
@foreach($results as $anime)
|
||||
<a href="{{ $anime->slug ? route('anime.show', $anime->slug) : '#' }}" class="a-card">
|
||||
<div class="a-poster">
|
||||
@if($anime->coverUrl)
|
||||
<img src="{{ $anime->coverUrl }}" alt="{{ $anime->title }}" loading="lazy">
|
||||
@else
|
||||
<div class="a-no-img"><i class="bi bi-image"></i></div>
|
||||
@endif
|
||||
@if($anime->type==='movie')<span class="a-badge">Film</span>@endif
|
||||
@if($anime->rating)<span class="a-rating"><i class="bi bi-star-fill" style="font-size:.65rem"></i>{{ number_format($anime->rating,1) }}</span>@endif
|
||||
<div class="a-hover-play"><div class="play-circle"><i class="bi bi-play-fill"></i></div></div>
|
||||
</div>
|
||||
<div class="a-info">
|
||||
<div class="a-title">{{ $anime->title }}</div>
|
||||
<div class="a-meta">{{ $anime->release_year }}@if($anime->episode_count) · {{ $anime->episode_count }}bö@endif</div>
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
@if($results->hasPages())
|
||||
<div style="margin-top:32px">{{ $results->links('frontend.pagination') }}</div>
|
||||
@endif
|
||||
@else
|
||||
<div style="text-align:center;padding:64px 20px;color:var(--text3)">
|
||||
<i class="bi bi-search" style="font-size:3rem;opacity:.25;display:block;margin-bottom:14px"></i>
|
||||
<p>Sonuç bulunamadı. Farklı bir arama terimi deneyin.</p>
|
||||
<a href="{{ route('search') }}" style="color:var(--accent);margin-top:12px;display:inline-block">Tümünü Göster</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,222 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Anime Mahkemesi | Animexe')
|
||||
@push('styles')
|
||||
<style>
|
||||
.trib-hero{padding-top:calc(var(--nav-h) + 40px);padding-bottom:32px;text-align:center;background:radial-gradient(ellipse at 50% 0%,rgba(255,45,125,.12) 0%,transparent 70%)}
|
||||
.trib-hero h1{font-size:2rem;font-weight:900;letter-spacing:-.02em;margin-bottom:8px}
|
||||
.trib-hero h1 span{color:#ff2d7d}
|
||||
.trib-hero p{color:rgba(255,255,255,.45);font-size:.95rem}
|
||||
.trib-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:16px;padding:0 0 40px}
|
||||
.trib-card{background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.07);border-radius:14px;padding:20px;transition:border-color .2s,transform .2s;cursor:pointer;text-decoration:none;display:block;color:#fff}
|
||||
.trib-card:hover{border-color:rgba(255,45,125,.3);transform:translateY(-2px)}
|
||||
.trib-card-anime{font-size:.72rem;color:rgba(255,45,125,.8);font-weight:700;text-transform:uppercase;letter-spacing:.08em;margin-bottom:8px}
|
||||
.trib-card-q{font-size:.98rem;font-weight:700;line-height:1.4;margin-bottom:14px}
|
||||
.trib-sides{display:flex;gap:8px;margin-bottom:14px}
|
||||
.trib-side{flex:1;padding:6px 10px;border-radius:8px;font-size:.75rem;font-weight:700;text-align:center}
|
||||
.trib-side.a{background:rgba(0,200,100,.1);color:#00c864;border:1px solid rgba(0,200,100,.2)}
|
||||
.trib-side.b{background:rgba(255,60,60,.1);color:#ff3c3c;border:1px solid rgba(255,60,60,.2)}
|
||||
.trib-side.c{background:rgba(59,130,246,.1);color:#3b82f6;border:1px solid rgba(59,130,246,.2)}
|
||||
.trib-side.d{background:rgba(245,158,11,.1);color:#f59e0b;border:1px solid rgba(245,158,11,.2)}
|
||||
.trib-side.e{background:rgba(167,139,250,.1);color:#a78bfa;border:1px solid rgba(167,139,250,.2)}
|
||||
.trib-side.f{background:rgba(236,72,153,.1);color:#ec4899;border:1px solid rgba(236,72,153,.2)}
|
||||
.trib-meta{display:flex;gap:12px;font-size:.72rem;color:rgba(255,255,255,.3)}
|
||||
.trib-status-open{color:#00c864;font-weight:700}
|
||||
.trib-status-closed{color:rgba(255,255,255,.3)}
|
||||
.trib-create-btn{display:inline-flex;align-items:center;gap:8px;padding:10px 24px;border-radius:20px;background:rgba(255,45,125,.15);border:1px solid rgba(255,45,125,.3);color:#ff2d7d;font-weight:700;font-size:.88rem;cursor:pointer;text-decoration:none;transition:all .15s;font-family:inherit}
|
||||
.trib-create-btn:hover{background:rgba(255,45,125,.28)}
|
||||
|
||||
/* Modal */
|
||||
.modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.7);z-index:1000;display:none;align-items:center;justify-content:center;padding:16px}
|
||||
.modal-overlay.on{display:flex}
|
||||
.modal-box{background:#0e0e1a;border:1px solid rgba(255,255,255,.1);border-radius:18px;padding:28px;width:100%;max-width:520px;max-height:90vh;overflow-y:auto}
|
||||
.modal-title{font-size:1.15rem;font-weight:900;margin-bottom:20px}
|
||||
.mf-label{font-size:.75rem;font-weight:700;color:rgba(255,255,255,.45);text-transform:uppercase;letter-spacing:.07em;margin-bottom:6px}
|
||||
.mf-input{width:100%;background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.1);border-radius:10px;padding:10px 14px;color:#fff;font-size:.9rem;font-family:inherit;outline:none;margin-bottom:14px;resize:none}
|
||||
.mf-row{display:grid;grid-template-columns:1fr 1fr;gap:12px}
|
||||
.mf-btn{width:100%;padding:12px;border-radius:12px;border:none;background:rgba(255,45,125,.2);color:#ff2d7d;font-weight:700;font-size:.9rem;cursor:pointer;font-family:inherit;transition:background .15s}
|
||||
.mf-btn:hover{background:rgba(255,45,125,.35)}
|
||||
</style>
|
||||
@endpush
|
||||
@section('content')
|
||||
<div style="max-width:1200px;margin:0 auto;padding:0 20px">
|
||||
|
||||
<div class="trib-hero">
|
||||
<h1>⚖️ Anime <span>Mahkemesi</span></h1>
|
||||
<p>Tartışmalı kararlar, karakterler, sahneler — topluluk yargılıyor.</p>
|
||||
@auth
|
||||
<br>
|
||||
<button class="trib-create-btn" onclick="document.getElementById('create-modal').classList.add('on')">
|
||||
<i class="bi bi-plus-lg"></i> Dava Aç
|
||||
</button>
|
||||
@endauth
|
||||
</div>
|
||||
|
||||
<div class="trib-grid">
|
||||
@forelse($tribunals as $t)
|
||||
<a class="trib-card" href="{{ route('tribunal.show', $t) }}">
|
||||
<div class="trib-card-anime">{{ $t->anime->title }}</div>
|
||||
<div class="trib-card-q">{{ $t->question }}</div>
|
||||
<div class="trib-sides" style="grid-template-columns:repeat({{ min(count($t->allSides()), 4) }},1fr)">
|
||||
@foreach($t->allSides() as $key => $label)
|
||||
<div class="trib-side {{ $key }}">{{ Str::limit($label, 20) }}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
<div class="trib-meta">
|
||||
<span class="trib-status-{{ $t->status }}">{{ $t->status === 'open' ? '🟢 Açık' : '🔴 Kapalı' }}</span>
|
||||
<span><i class="bi bi-people"></i> {{ $t->votes_count }} oy</span>
|
||||
<span>{{ $t->created_at->diffForHumans() }}</span>
|
||||
</div>
|
||||
</a>
|
||||
@empty
|
||||
<div style="grid-column:1/-1;text-align:center;padding:60px;color:rgba(255,255,255,.3)">
|
||||
<i class="bi bi-balance" style="font-size:3rem;display:block;margin-bottom:12px"></i>
|
||||
Henüz dava açılmamış.
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
{{ $tribunals->links('frontend.pagination') }}
|
||||
|
||||
</div>
|
||||
|
||||
{{-- Dava Açma Modalı --}}
|
||||
@auth
|
||||
<div class="modal-overlay" id="create-modal" onclick="if(event.target===this)this.classList.remove('on')">
|
||||
<div class="modal-box">
|
||||
<div class="modal-title">⚖️ Yeni Dava Aç</div>
|
||||
<div class="mf-label">Anime</div>
|
||||
<input class="mf-input" type="text" id="cm-anime-search" placeholder="Anime adı ara..." autocomplete="off" oninput="searchAnime(this.value)">
|
||||
<div id="cm-anime-results" style="margin-bottom:14px;display:none;background:rgba(0,0,0,.4);border:1px solid rgba(255,255,255,.1);border-radius:10px;overflow:hidden;max-height:160px;overflow-y:auto"></div>
|
||||
<input type="hidden" id="cm-anime-id">
|
||||
|
||||
<div class="mf-label">Soru / Karar</div>
|
||||
<textarea class="mf-input" id="cm-question" rows="2" maxlength="280" placeholder="Örn: Sasuke'nin Konoha'yı terk etmesi doğru muydu?"></textarea>
|
||||
|
||||
<div id="cm-sides-wrap">
|
||||
<div class="mf-row" style="margin-bottom:0">
|
||||
<div>
|
||||
<div class="mf-label" style="color:#00c864">Taraf A (Yeşil)</div>
|
||||
<input class="mf-input" id="cm-side-a" maxlength="100" placeholder="Örn: Haklıydı">
|
||||
</div>
|
||||
<div>
|
||||
<div class="mf-label" style="color:#ff3c3c">Taraf B (Kırmızı)</div>
|
||||
<input class="mf-input" id="cm-side-b" maxlength="100" placeholder="Örn: Haksızdı">
|
||||
</div>
|
||||
</div>
|
||||
<div id="cm-extra-sides"></div>
|
||||
</div>
|
||||
<div style="margin-bottom:14px">
|
||||
<button type="button" id="cm-add-side-btn" onclick="addExtraSide()"
|
||||
style="background:none;border:1px dashed rgba(255,255,255,.2);border-radius:8px;color:rgba(255,255,255,.4);font-size:.78rem;padding:6px 14px;cursor:pointer;font-family:inherit;transition:all .15s;width:100%"
|
||||
onmouseover="this.style.borderColor='rgba(255,255,255,.4)';this.style.color='#fff'"
|
||||
onmouseout="this.style.borderColor='rgba(255,255,255,.2)';this.style.color='rgba(255,255,255,.4)'">
|
||||
<i class="bi bi-plus-lg"></i> Seçenek Ekle (max 4 ekstra)
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mf-label">Kapanış Tarihi (isteğe bağlı)</div>
|
||||
<input class="mf-input" type="date" id="cm-closes-at" min="{{ now()->addDay()->format('Y-m-d') }}">
|
||||
|
||||
<div id="cm-error" style="color:#ff4444;font-size:.8rem;margin-bottom:10px;display:none"></div>
|
||||
<button class="mf-btn" onclick="submitTribunal()">Davayı Aç</button>
|
||||
</div>
|
||||
</div>
|
||||
@endauth
|
||||
|
||||
@endsection
|
||||
@push('scripts')
|
||||
<script>
|
||||
const CSRF = document.querySelector('meta[name="csrf-token"]')?.content ?? '';
|
||||
let animeSearchTimer = null;
|
||||
|
||||
function searchAnime(q) {
|
||||
clearTimeout(animeSearchTimer);
|
||||
if (q.length < 2) { document.getElementById('cm-anime-results').style.display = 'none'; return; }
|
||||
animeSearchTimer = setTimeout(async () => {
|
||||
const r = await fetch(`/search?q=${encodeURIComponent(q)}&json=1`);
|
||||
if (!r.ok) return;
|
||||
const d = await r.json();
|
||||
const res = document.getElementById('cm-anime-results');
|
||||
const items = (d.animes || d.results || []).slice(0, 6);
|
||||
if (!items.length) { res.style.display = 'none'; return; }
|
||||
res.style.display = 'block';
|
||||
res.innerHTML = items.map(a => `<div onclick="selectAnime(${a.id},'${a.title.replace(/'/g,"\\'")}')"
|
||||
style="padding:8px 12px;cursor:pointer;font-size:.85rem;border-bottom:1px solid rgba(255,255,255,.05);display:flex;align-items:center;gap:10px"
|
||||
onmouseover="this.style.background='rgba(255,255,255,.07)'" onmouseout="this.style.background=''">
|
||||
${a.cover ? `<img src="${a.cover}" style="width:28px;height:40px;object-fit:cover;border-radius:3px;flex-shrink:0">` : '<div style="width:28px;height:40px;background:#222;border-radius:3px;flex-shrink:0"></div>'}
|
||||
<span>${a.title}</span>
|
||||
</div>`).join('');
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function selectAnime(id, title) {
|
||||
document.getElementById('cm-anime-id').value = id;
|
||||
document.getElementById('cm-anime-search').value = title;
|
||||
document.getElementById('cm-anime-results').style.display = 'none';
|
||||
}
|
||||
|
||||
const SIDE_COLORS = ['#00c864','#ff3c3c','#3b82f6','#f59e0b','#a78bfa','#ec4899'];
|
||||
const SIDE_NAMES = ['A (Yeşil)','B (Kırmızı)','C (Mavi)','D (Turuncu)','E (Mor)','F (Pembe)'];
|
||||
let extraSideCount = 0;
|
||||
|
||||
function addExtraSide() {
|
||||
if (extraSideCount >= 4) return;
|
||||
extraSideCount++;
|
||||
const idx = extraSideCount + 1; // 0=a,1=b, so extra starts at 2 (c)
|
||||
const color = SIDE_COLORS[idx] || '#ffffff';
|
||||
const name = SIDE_NAMES[idx] || ('Seçenek ' + (idx+1));
|
||||
const wrap = document.getElementById('cm-extra-sides');
|
||||
const div = document.createElement('div');
|
||||
div.id = 'cm-extra-' + extraSideCount;
|
||||
div.style.marginTop = '10px';
|
||||
div.innerHTML = `
|
||||
<div style="display:flex;align-items:center;gap:6px">
|
||||
<div style="font-size:.72rem;font-weight:700;color:${color};text-transform:uppercase;letter-spacing:.07em;white-space:nowrap">Taraf ${name}</div>
|
||||
<button type="button" onclick="removeExtraSide(${extraSideCount})"
|
||||
style="margin-left:auto;background:none;border:none;color:rgba(255,80,80,.5);cursor:pointer;font-size:.8rem;padding:0 4px">✕</button>
|
||||
</div>
|
||||
<input class="mf-input" id="cm-extra-val-${extraSideCount}" maxlength="100" placeholder="Seçenek metni..." style="margin-top:4px">`;
|
||||
wrap.appendChild(div);
|
||||
if (extraSideCount >= 4) document.getElementById('cm-add-side-btn').style.display = 'none';
|
||||
}
|
||||
|
||||
function removeExtraSide(n) {
|
||||
document.getElementById('cm-extra-' + n)?.remove();
|
||||
extraSideCount = Math.max(0, extraSideCount - 1);
|
||||
document.getElementById('cm-add-side-btn').style.display = '';
|
||||
// Renumber visible extras
|
||||
const extras = document.getElementById('cm-extra-sides').children;
|
||||
extraSideCount = extras.length;
|
||||
}
|
||||
|
||||
async function submitTribunal() {
|
||||
const err = document.getElementById('cm-error');
|
||||
err.style.display = 'none';
|
||||
const animeId = document.getElementById('cm-anime-id').value;
|
||||
const question = document.getElementById('cm-question').value.trim();
|
||||
const sideA = document.getElementById('cm-side-a').value.trim();
|
||||
const sideB = document.getElementById('cm-side-b').value.trim();
|
||||
const closesAt = document.getElementById('cm-closes-at').value;
|
||||
|
||||
// Extra sides
|
||||
const extraSides = [];
|
||||
for (let i = 1; i <= 4; i++) {
|
||||
const v = document.getElementById('cm-extra-val-' + i)?.value.trim();
|
||||
if (v) extraSides.push(v);
|
||||
}
|
||||
|
||||
if (!animeId) { err.textContent = 'Anime seçin.'; err.style.display = 'block'; return; }
|
||||
if (question.length < 10) { err.textContent = 'Soru en az 10 karakter olmalı.'; err.style.display = 'block'; return; }
|
||||
if (!sideA || !sideB) { err.textContent = 'A ve B taraflarını doldurun.'; err.style.display = 'block'; return; }
|
||||
|
||||
const r = await fetch('/mahkeme', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': CSRF, 'Accept': 'application/json' },
|
||||
body: JSON.stringify({ anime_id: animeId, question, side_a: sideA, side_b: sideB, extra_sides: extraSides, closes_at: closesAt || null }),
|
||||
});
|
||||
const d = await r.json();
|
||||
if (d.url) window.location.href = d.url;
|
||||
else { err.textContent = d.error || 'Hata oluştu.'; err.style.display = 'block'; }
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,253 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Mahkeme: ' . Str::limit($tribunal->question, 60) . ' | Animexe')
|
||||
@php
|
||||
// Sabit renk paleti — a,b,c,d,e,f
|
||||
$palette = [
|
||||
'a' => ['bg'=>'rgba(0,200,100,.08)', 'bg2'=>'rgba(0,200,100,.22)', 'border'=>'rgba(0,200,100,.25)', 'border2'=>'#00c864', 'text'=>'#00c864', 'bar'=>'#00c864'],
|
||||
'b' => ['bg'=>'rgba(255,60,60,.08)', 'bg2'=>'rgba(255,60,60,.22)', 'border'=>'rgba(255,60,60,.25)', 'border2'=>'#ff3c3c', 'text'=>'#ff3c3c', 'bar'=>'#ff3c3c'],
|
||||
'c' => ['bg'=>'rgba(59,130,246,.08)', 'bg2'=>'rgba(59,130,246,.22)', 'border'=>'rgba(59,130,246,.25)', 'border2'=>'#3b82f6', 'text'=>'#3b82f6', 'bar'=>'#3b82f6'],
|
||||
'd' => ['bg'=>'rgba(245,158,11,.08)', 'bg2'=>'rgba(245,158,11,.22)', 'border'=>'rgba(245,158,11,.25)', 'border2'=>'#f59e0b', 'text'=>'#f59e0b', 'bar'=>'#f59e0b'],
|
||||
'e' => ['bg'=>'rgba(167,139,250,.08)','bg2'=>'rgba(167,139,250,.22)','border'=>'rgba(167,139,250,.25)','border2'=>'#a78bfa','text'=>'#a78bfa','bar'=>'#a78bfa'],
|
||||
'f' => ['bg'=>'rgba(236,72,153,.08)', 'bg2'=>'rgba(236,72,153,.22)', 'border'=>'rgba(236,72,153,.25)', 'border2'=>'#ec4899','text'=>'#ec4899','bar'=>'#ec4899'],
|
||||
];
|
||||
$cols = count($allSides) <= 2 ? '1fr 1fr' : (count($allSides) <= 3 ? '1fr 1fr 1fr' : 'repeat(auto-fit,minmax(140px,1fr))');
|
||||
@endphp
|
||||
@push('styles')
|
||||
<style>
|
||||
.tb-wrap{max-width:900px;margin:0 auto;padding:calc(var(--nav-h) + 32px) 20px 60px}
|
||||
.tb-anime-link{font-size:.75rem;color:rgba(255,45,125,.8);font-weight:700;text-transform:uppercase;letter-spacing:.08em;text-decoration:none;display:inline-block;margin-bottom:12px}
|
||||
.tb-question{font-size:1.5rem;font-weight:900;line-height:1.35;margin-bottom:14px}
|
||||
.tb-status{display:inline-block;padding:3px 12px;border-radius:20px;font-size:.72rem;font-weight:700;margin-bottom:20px}
|
||||
.tb-status.open{background:rgba(0,200,100,.15);color:#00c864;border:1px solid rgba(0,200,100,.25)}
|
||||
.tb-status.closed{background:rgba(255,255,255,.06);color:rgba(255,255,255,.4);border:1px solid rgba(255,255,255,.1)}
|
||||
|
||||
/* Vote Card */
|
||||
.tb-votebar{background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);border-radius:16px;padding:24px;margin-bottom:24px}
|
||||
.tb-sides{display:grid;gap:10px;margin-bottom:20px;grid-template-columns:{{ $cols }}}
|
||||
.tb-vote-btn{padding:13px 10px;border-radius:12px;border:2px solid transparent;cursor:pointer;font-weight:800;font-size:.88rem;font-family:inherit;transition:all .2s;text-align:center;line-height:1.3}
|
||||
|
||||
/* Multi-bar */
|
||||
.tb-multibar{display:flex;flex-direction:column;gap:8px}
|
||||
.tb-bar-row{display:flex;align-items:center;gap:10px}
|
||||
.tb-bar-label{font-size:.72rem;font-weight:700;white-space:nowrap;min-width:80px;max-width:120px;overflow:hidden;text-overflow:ellipsis}
|
||||
.tb-bar-track{flex:1;height:8px;border-radius:99px;background:rgba(255,255,255,.07);overflow:hidden}
|
||||
.tb-bar-fill{height:100%;border-radius:99px;transition:width .5s cubic-bezier(.22,1,.36,1)}
|
||||
.tb-bar-pct{font-size:.72rem;color:rgba(255,255,255,.4);min-width:40px;text-align:right}
|
||||
|
||||
/* Arguments */
|
||||
.tb-args{margin-top:28px}
|
||||
.tb-args-title{font-size:.8rem;font-weight:700;text-transform:uppercase;letter-spacing:.1em;color:rgba(255,255,255,.3);margin-bottom:16px}
|
||||
.tb-arg-card{background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.07);border-radius:12px;padding:16px;margin-bottom:10px}
|
||||
.tb-arg-side-badge{display:inline-block;padding:2px 10px;border-radius:20px;font-size:.68rem;font-weight:800;margin-bottom:8px}
|
||||
.tb-arg-body{font-size:.9rem;line-height:1.5;margin-bottom:10px}
|
||||
.tb-arg-meta{display:flex;align-items:center;gap:12px;font-size:.72rem;color:rgba(255,255,255,.3)}
|
||||
.tb-arg-vote-btn{background:none;border:1px solid rgba(255,255,255,.1);border-radius:20px;padding:3px 12px;color:rgba(255,255,255,.4);cursor:pointer;font-size:.72rem;font-family:inherit;display:inline-flex;align-items:center;gap:5px;transition:all .15s}
|
||||
.tb-arg-vote-btn:hover,.tb-arg-vote-btn.on{background:rgba(255,215,0,.12);border-color:rgba(255,215,0,.3);color:#ffd700}
|
||||
|
||||
/* Argue form */
|
||||
.tb-argue-form{background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.07);border-radius:14px;padding:20px;margin-top:24px}
|
||||
.tb-argue-title{font-size:.88rem;font-weight:700;margin-bottom:12px}
|
||||
.tb-argue-sides{display:grid;gap:8px;margin-bottom:12px;grid-template-columns:{{ $cols }}}
|
||||
.tb-argue-side-btn{padding:9px 8px;border-radius:10px;cursor:pointer;font-weight:700;font-size:.8rem;font-family:inherit;border:2px solid transparent;transition:all .15s;text-align:center}
|
||||
textarea.tb-inp{width:100%;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1);border-radius:10px;padding:10px 14px;color:#fff;font-size:.88rem;font-family:inherit;resize:none;outline:none;margin-bottom:10px;box-sizing:border-box}
|
||||
.tb-submit-btn{padding:10px 24px;border-radius:10px;border:none;background:rgba(255,45,125,.2);color:#ff2d7d;font-weight:700;font-size:.88rem;cursor:pointer;font-family:inherit;transition:background .15s}
|
||||
.tb-submit-btn:hover{background:rgba(255,45,125,.35)}
|
||||
</style>
|
||||
@endpush
|
||||
@section('content')
|
||||
<div class="tb-wrap">
|
||||
|
||||
<a class="tb-anime-link" href="{{ $tribunal->anime?->detailUrl ?? '#' }}">
|
||||
<i class="bi bi-arrow-left"></i> {{ $tribunal->anime->title }}
|
||||
</a>
|
||||
|
||||
<div class="tb-status {{ $tribunal->status }}">
|
||||
{{ $tribunal->status === 'open' ? '🟢 Dava Açık' : '🔴 Dava Kapalı' }}
|
||||
@if($tribunal->closes_at && $tribunal->status === 'open')
|
||||
· {{ $tribunal->closes_at->diffForHumans() }} kapanıyor
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="tb-question">{{ $tribunal->question }}</div>
|
||||
|
||||
{{-- Oy sistemi --}}
|
||||
<div class="tb-votebar">
|
||||
<div class="tb-sides">
|
||||
@foreach($allSides as $key => $label)
|
||||
@php $c = $palette[$key] ?? $palette['a']; @endphp
|
||||
<button id="vote-{{ $key }}" class="tb-vote-btn"
|
||||
style="background:{{ $c['bg'] }};color:{{ $c['text'] }};border-color:{{ $c['border'] }}"
|
||||
data-bg="{{ $c['bg'] }}" data-bg2="{{ $c['bg2'] }}" data-border="{{ $c['border'] }}" data-border2="{{ $c['border2'] }}"
|
||||
onclick="castVote('{{ $key }}')">
|
||||
{{ $label }}
|
||||
<div style="font-size:.7rem;font-weight:400;opacity:.7;margin-top:3px">
|
||||
<span id="vcnt-{{ $key }}">{{ $voteCounts[$key] ?? 0 }}</span> oy
|
||||
· <span id="vpct-{{ $key }}">{{ $total > 0 ? round(($voteCounts[$key]??0)/$total*100) : 0 }}%</span>
|
||||
</div>
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
{{-- Çok taraflı bar --}}
|
||||
<div class="tb-multibar">
|
||||
@foreach($allSides as $key => $label)
|
||||
@php $c = $palette[$key] ?? $palette['a']; $pct = $total > 0 ? round(($voteCounts[$key]??0)/$total*100) : 0; @endphp
|
||||
<div class="tb-bar-row">
|
||||
<div class="tb-bar-label" style="color:{{ $c['text'] }}">{{ $label }}</div>
|
||||
<div class="tb-bar-track">
|
||||
<div class="tb-bar-fill" id="bar-{{ $key }}" style="width:{{ $pct }}%;background:{{ $c['bar'] }}"></div>
|
||||
</div>
|
||||
<div class="tb-bar-pct" id="bpct-{{ $key }}">{{ $pct }}%</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div style="margin-top:10px;font-size:.72rem;color:rgba(255,255,255,.25)">
|
||||
Toplam <span id="total-votes">{{ $total }}</span> oy
|
||||
@auth @if($myVote) · <span style="color:rgba(255,255,255,.5)">Oyunuz: <strong>{{ $allSides[$myVote] ?? $myVote }}</strong></span> @endif @endauth
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Argümanlar --}}
|
||||
<div class="tb-args">
|
||||
<div class="tb-args-title"><i class="bi bi-chat-quote"></i> Argümanlar</div>
|
||||
<div id="arg-list">
|
||||
@forelse($arguments as $arg)
|
||||
@php $c2 = $palette[$arg['side']] ?? $palette['a']; @endphp
|
||||
<div class="tb-arg-card" id="arg-{{ $arg['id'] }}">
|
||||
<span class="tb-arg-side-badge"
|
||||
style="background:{{ $c2['bg'] }};color:{{ $c2['text'] }}">{{ $allSides[$arg['side']] ?? $arg['side'] }}</span>
|
||||
<div class="tb-arg-body">{{ $arg['body'] }}</div>
|
||||
<div class="tb-arg-meta">
|
||||
<span>{{ $arg['name'] ?? $arg['username'] }}</span>
|
||||
<span>{{ $arg['created_at'] }}</span>
|
||||
<button class="tb-arg-vote-btn {{ $arg['voted'] ? 'on' : '' }}" id="avgbtn-{{ $arg['id'] }}"
|
||||
onclick="argVote({{ $arg['id'] }})">
|
||||
<i class="bi bi-hand-thumbs-up"></i>
|
||||
<span id="avgcnt-{{ $arg['id'] }}">{{ $arg['vote_count'] }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div id="no-args" style="text-align:center;padding:30px;color:rgba(255,255,255,.25);font-size:.85rem">
|
||||
Henüz argüman girilmemiş. İlk sen gir!
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Argüman formu --}}
|
||||
@auth
|
||||
@if(!$myArgument && $tribunal->status === 'open')
|
||||
<div class="tb-argue-form">
|
||||
<div class="tb-argue-title">⚔️ Senin Argümanın — Hangi taraftasın?</div>
|
||||
<div class="tb-argue-sides">
|
||||
@foreach($allSides as $key => $label)
|
||||
@php $c3 = $palette[$key] ?? $palette['a']; @endphp
|
||||
<button id="arg-side-{{ $key }}" class="tb-argue-side-btn"
|
||||
style="background:{{ $c3['bg'] }};color:{{ $c3['text'] }};border-color:{{ $c3['border'] }}"
|
||||
data-bg="{{ $c3['bg'] }}" data-bg2="{{ $c3['bg2'] }}" data-border="{{ $c3['border'] }}" data-border2="{{ $c3['border2'] }}"
|
||||
onclick="selectArgSide('{{ $key }}')">{{ $label }}</button>
|
||||
@endforeach
|
||||
</div>
|
||||
<textarea class="tb-inp" id="arg-body" rows="3" maxlength="500" placeholder="Argümanını yaz (min 10, max 500 karakter)..."></textarea>
|
||||
<div id="arg-err" style="color:#ff4444;font-size:.78rem;margin-bottom:8px;display:none"></div>
|
||||
<button class="tb-submit-btn" onclick="submitArg()">Argümanı Gönder</button>
|
||||
</div>
|
||||
@elseif($myArgument)
|
||||
<div style="padding:14px;background:rgba(0,200,100,.06);border:1px solid rgba(0,200,100,.2);border-radius:12px;font-size:.85rem;color:rgba(255,255,255,.5);margin-top:24px">
|
||||
✅ Argümanınızı gönderdiniz.
|
||||
</div>
|
||||
@endif
|
||||
@else
|
||||
<div style="margin-top:20px;text-align:center;font-size:.85rem;color:rgba(255,255,255,.3)">
|
||||
<a href="{{ route('frontend.login') }}" style="color:#ff2d7d">Giriş yap</a> — argüman girmek için
|
||||
</div>
|
||||
@endauth
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
@push('scripts')
|
||||
<script>
|
||||
const CSRF = document.querySelector('meta[name="csrf-token"]')?.content ?? '';
|
||||
const IS_AUTH = {{ auth()->check() ? 'true' : 'false' }};
|
||||
const MY_VOTE = {{ $myVote ? json_encode($myVote) : 'null' }};
|
||||
let selectedArgSide = null;
|
||||
|
||||
// İlk yüklemede aktif oyu vurgula
|
||||
if (MY_VOTE) activateVoteBtn(MY_VOTE);
|
||||
|
||||
function activateVoteBtn(side) {
|
||||
document.querySelectorAll('.tb-vote-btn').forEach(b => {
|
||||
const isMe = b.id === 'vote-' + side;
|
||||
b.style.background = isMe ? b.dataset.bg2 : b.dataset.bg;
|
||||
b.style.borderColor = isMe ? b.dataset.border2 : b.dataset.border;
|
||||
});
|
||||
}
|
||||
|
||||
function selectArgSide(s) {
|
||||
selectedArgSide = s;
|
||||
document.querySelectorAll('.tb-argue-side-btn').forEach(b => {
|
||||
const isMe = b.id === 'arg-side-' + s;
|
||||
b.style.background = isMe ? b.dataset.bg2 : b.dataset.bg;
|
||||
b.style.borderColor = isMe ? b.dataset.border2 : b.dataset.border;
|
||||
});
|
||||
}
|
||||
|
||||
async function castVote(side) {
|
||||
if (!IS_AUTH) { window.location.href = '{{ route('frontend.login') }}'; return; }
|
||||
const r = await fetch('{{ route('tribunal.vote', $tribunal) }}', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': CSRF, 'Accept': 'application/json' },
|
||||
body: JSON.stringify({ side }),
|
||||
});
|
||||
const d = await r.json();
|
||||
updateVoteBar(d.voted, d.counts, d.total);
|
||||
}
|
||||
|
||||
function updateVoteBar(voted, counts, total) {
|
||||
activateVoteBtn(voted);
|
||||
document.getElementById('total-votes').textContent = total;
|
||||
for (const [key, cnt] of Object.entries(counts)) {
|
||||
const pct = total > 0 ? Math.round(cnt / total * 100) : 0;
|
||||
const fill = document.getElementById('bar-' + key);
|
||||
const pctEl = document.getElementById('bpct-' + key);
|
||||
const vcnt = document.getElementById('vcnt-' + key);
|
||||
const vpct = document.getElementById('vpct-' + key);
|
||||
if (fill) fill.style.width = pct + '%';
|
||||
if (pctEl) pctEl.textContent = pct + '%';
|
||||
if (vcnt) vcnt.textContent = cnt;
|
||||
if (vpct) vpct.textContent = pct + '%';
|
||||
}
|
||||
}
|
||||
|
||||
async function argVote(id) {
|
||||
if (!IS_AUTH) { window.location.href = '{{ route('frontend.login') }}'; return; }
|
||||
const r = await fetch(`/arguman/${id}/oy`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': CSRF, 'Accept': 'application/json' },
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
const d = await r.json();
|
||||
document.getElementById('avgcnt-' + id).textContent = d.vote_count;
|
||||
document.getElementById('avgbtn-' + id).classList.toggle('on', d.voted);
|
||||
}
|
||||
|
||||
async function submitArg() {
|
||||
const err = document.getElementById('arg-err');
|
||||
const body = document.getElementById('arg-body').value.trim();
|
||||
err.style.display = 'none';
|
||||
if (!selectedArgSide) { err.textContent = 'Taraf seçin.'; err.style.display = 'block'; return; }
|
||||
if (body.length < 10) { err.textContent = 'Argüman en az 10 karakter olmalı.'; err.style.display = 'block'; return; }
|
||||
|
||||
const r = await fetch('{{ route('tribunal.argue', $tribunal) }}', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': CSRF, 'Accept': 'application/json' },
|
||||
body: JSON.stringify({ side: selectedArgSide, body }),
|
||||
});
|
||||
const d = await r.json();
|
||||
if (d.ok) window.location.reload();
|
||||
else { err.textContent = d.error || 'Hata.'; err.style.display = 'block'; }
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,274 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('title', 'Watch Party — ' . $party->episode->anime->title . ' | Animexe')
|
||||
@push('styles')
|
||||
<style>
|
||||
body{background:#05050e}
|
||||
#pg{padding-top:0}
|
||||
.wp-wrap{display:flex;max-width:1600px;margin:0 auto;padding-top:var(--nav-h);min-height:calc(100vh - var(--nav-h));gap:0}
|
||||
.wp-main{flex:1;min-width:0;background:#020208;display:flex;flex-direction:column}
|
||||
.wp-side{width:320px;flex-shrink:0;background:rgba(10,10,22,.98);border-left:1px solid rgba(255,45,125,.15);display:flex;flex-direction:column;height:calc(100vh - var(--nav-h));position:sticky;top:var(--nav-h)}
|
||||
|
||||
/* Video */
|
||||
.wp-vwrap{position:relative;width:100%;aspect-ratio:16/9;background:#000}
|
||||
.wp-vwrap iframe,.wp-vwrap video{position:absolute;inset:0;width:100%;height:100%;border:none}
|
||||
|
||||
/* Host bar */
|
||||
.wp-hostbar{padding:12px 16px;background:rgba(255,45,125,.06);border-bottom:1px solid rgba(255,45,125,.15);display:flex;align-items:center;gap:12px;flex-wrap:wrap}
|
||||
.wp-roomcode{font-size:1.4rem;font-weight:900;letter-spacing:.18em;color:#ff2d7d;cursor:pointer;user-select:all}
|
||||
.wp-hostbtn{padding:6px 16px;border-radius:20px;border:1px solid rgba(255,45,125,.4);background:rgba(255,45,125,.1);color:#ff2d7d;font-size:.8rem;font-weight:700;cursor:pointer;font-family:inherit;transition:all .15s}
|
||||
.wp-hostbtn:hover{background:rgba(255,45,125,.25)}
|
||||
.wp-sync-status{font-size:.72rem;color:rgba(255,255,255,.3);margin-left:auto}
|
||||
|
||||
/* Members */
|
||||
.wp-members{padding:12px 16px;border-bottom:1px solid rgba(255,255,255,.06)}
|
||||
.wp-members-title{font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.1em;color:rgba(255,255,255,.3);margin-bottom:8px}
|
||||
.wp-member-list{display:flex;flex-wrap:wrap;gap:6px}
|
||||
.wp-member{display:flex;align-items:center;gap:6px;padding:4px 10px;background:rgba(255,255,255,.06);border-radius:20px;font-size:.76rem;color:#fff}
|
||||
.wp-member.host{border:1px solid rgba(255,215,0,.3);background:rgba(255,215,0,.06)}
|
||||
|
||||
/* Chat */
|
||||
.wp-chat{flex:1;overflow-y:auto;padding:12px 16px;display:flex;flex-direction:column;gap:8px;scroll-behavior:smooth}
|
||||
.wc-msg{max-width:100%}
|
||||
.wc-meta{font-size:.68rem;color:rgba(255,255,255,.3);margin-bottom:3px}
|
||||
.wc-bubble{display:inline-block;padding:7px 12px;border-radius:0 10px 10px 10px;background:rgba(255,255,255,.07);font-size:.84rem;color:#fff;word-break:break-word;max-width:100%;line-height:1.4}
|
||||
.wc-mine .wc-bubble{background:rgba(255,45,125,.15);border-radius:10px 0 10px 10px}
|
||||
.wc-mine{align-self:flex-end;text-align:right}
|
||||
.wc-mine .wc-meta{text-align:right}
|
||||
|
||||
/* Chat input */
|
||||
.wp-chat-input{padding:12px 16px;border-top:1px solid rgba(255,255,255,.07);display:flex;gap:8px;flex-shrink:0}
|
||||
.wp-chat-input input{flex:1;background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.1);border-radius:10px;padding:9px 14px;color:#fff;font-size:.84rem;font-family:inherit;outline:none}
|
||||
.wp-chat-input button{padding:9px 16px;border-radius:10px;border:none;background:rgba(255,45,125,.2);color:#ff2d7d;font-size:.9rem;cursor:pointer;flex-shrink:0;transition:background .15s}
|
||||
.wp-chat-input button:hover{background:rgba(255,45,125,.35)}
|
||||
|
||||
/* Episode info */
|
||||
.wp-ep-info{padding:14px 16px;border-bottom:1px solid rgba(255,255,255,.06);display:flex;gap:12px;align-items:center}
|
||||
.wp-ep-info img{width:48px;height:72px;border-radius:8px;object-fit:cover;flex-shrink:0}
|
||||
.wp-ep-title{font-size:.84rem;font-weight:700;color:#fff;margin-bottom:2px}
|
||||
.wp-ep-sub{font-size:.72rem;color:rgba(255,255,255,.35)}
|
||||
</style>
|
||||
@endpush
|
||||
@section('content')
|
||||
<div class="wp-wrap">
|
||||
|
||||
{{-- ── Ana video alanı ─────────────────────────────────────────── --}}
|
||||
<div class="wp-main">
|
||||
|
||||
{{-- Video --}}
|
||||
<div class="wp-vwrap" id="wp-vwrap">
|
||||
@if($party->episode->m3u8_url || $party->episode->video_url)
|
||||
<video id="wp-vd" controls playsinline preload="metadata"
|
||||
@if($party->episode->m3u8_url) data-src="{{ $party->episode->m3u8_url }}" @endif
|
||||
@if($party->episode->video_url) src="{{ $party->episode->video_url }}" @endif>
|
||||
</video>
|
||||
@else
|
||||
<div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:rgba(255,255,255,.3);font-size:.9rem">
|
||||
<div style="text-align:center"><i class="bi bi-play-circle" style="font-size:3rem;display:block;margin-bottom:8px"></i>Video yüklenemedi</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Host kontrol barı --}}
|
||||
<div class="wp-hostbar">
|
||||
<div>
|
||||
<div style="font-size:.68rem;color:rgba(255,255,255,.3);margin-bottom:2px">Oda Kodu</div>
|
||||
<div class="wp-roomcode" onclick="copyCode()" title="Kopyalamak için tıkla">{{ $party->room_code }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-size:.68rem;color:rgba(255,255,255,.3);margin-bottom:4px">
|
||||
Ev Sahibi: <span id="wp-host-name" style="color:#fff">{{ $party->host->name ?? '—' }}</span>
|
||||
@auth @if(auth()->id() === $party->host_user_id)
|
||||
<span style="background:rgba(255,215,0,.15);color:#ffd700;padding:1px 7px;border-radius:10px;font-size:.65rem;margin-left:5px">Sensin</span>
|
||||
@endif @endauth
|
||||
</div>
|
||||
<div id="wp-member-count" style="font-size:.72rem;color:rgba(255,255,255,.35)">0 üye aktif</div>
|
||||
</div>
|
||||
@auth @if(auth()->id() === $party->host_user_id)
|
||||
<button class="wp-hostbtn" onclick="hostPlay()"><i class="bi bi-play-fill"></i> Oynat</button>
|
||||
<button class="wp-hostbtn" onclick="hostPause()"><i class="bi bi-pause-fill"></i> Durdur</button>
|
||||
@endif @endauth
|
||||
<span class="wp-sync-status" id="wp-sync-status">⏱ bekleniyor...</span>
|
||||
<a href="{{ route('watch', [$party->episode->anime->slug, $party->episode->season->season_number ?? 1, $party->episode->episode_number]) }}"
|
||||
style="margin-left:auto;font-size:.76rem;color:rgba(255,255,255,.3);text-decoration:none">
|
||||
<i class="bi bi-box-arrow-up-right"></i> Tam oynatıcı
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{-- ── Sağ panel: Üyeler + Chat ─────────────────────────────────── --}}
|
||||
<div class="wp-side">
|
||||
|
||||
{{-- Bölüm bilgisi --}}
|
||||
<div class="wp-ep-info">
|
||||
@if($party->episode->anime->coverUrl)
|
||||
<img src="{{ $party->episode->anime->coverUrl }}" alt="">
|
||||
@endif
|
||||
<div>
|
||||
<div class="wp-ep-title">{{ $party->episode->anime->title }}</div>
|
||||
<div class="wp-ep-sub">S{{ $party->episode->season->season_number ?? 1 }}E{{ $party->episode->episode_number }}
|
||||
{{ $party->episode->title ? '— ' . $party->episode->title : '' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Aktif üyeler --}}
|
||||
<div class="wp-members">
|
||||
<div class="wp-members-title"><i class="bi bi-people"></i> Aktif Üyeler</div>
|
||||
<div class="wp-member-list" id="wp-members"></div>
|
||||
</div>
|
||||
|
||||
{{-- Chat --}}
|
||||
<div class="wp-chat" id="wp-chat"></div>
|
||||
|
||||
{{-- Chat input --}}
|
||||
@auth
|
||||
<div class="wp-chat-input">
|
||||
<input type="text" id="wp-chat-inp" placeholder="Mesaj yaz..." maxlength="200"
|
||||
onkeydown="if(event.key==='Enter')sendChatMsg()">
|
||||
<button onclick="sendChatMsg()"><i class="bi bi-send-fill"></i></button>
|
||||
</div>
|
||||
@else
|
||||
<div style="padding:12px;text-align:center;font-size:.78rem;color:rgba(255,255,255,.3)">
|
||||
<a href="{{ route('frontend.login') }}" style="color:#ff2d7d">Giriş yap</a> — sohbete katıl
|
||||
</div>
|
||||
@endauth
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
@push('scripts')
|
||||
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
|
||||
<script>
|
||||
const WP_CSRF = document.querySelector('meta[name="csrf-token"]')?.content ?? '';
|
||||
const WP_ROOM = '{{ $party->room_code }}';
|
||||
const WP_IS_HOST = {{ auth()->check() && auth()->id() === $party->host_user_id ? 'true' : 'false' }};
|
||||
const WP_ME_NAME = {{ auth()->check() ? json_encode(auth()->user()->name) : 'null' }};
|
||||
const WP_IS_AUTH = {{ auth()->check() ? 'true' : 'false' }};
|
||||
|
||||
// HLS init
|
||||
const vd = document.getElementById('wp-vd');
|
||||
if (vd) {
|
||||
const src = vd.dataset.src;
|
||||
if (src && Hls.isSupported()) {
|
||||
const hls = new Hls();
|
||||
hls.loadSource(src);
|
||||
hls.attachMedia(vd);
|
||||
} else if (src && vd.canPlayType('application/vnd.apple.mpegurl')) {
|
||||
vd.src = src;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Chat (basit localStorage tabanlı, polling) ────────────────
|
||||
// Gerçek WebSocket olmadığı için sync sırasında chat mesajlarını da taşı
|
||||
let chatMessages = [];
|
||||
let lastChatTs = 0;
|
||||
|
||||
function addChatMsg(msg, isMine) {
|
||||
chatMessages.push({ ...msg, mine: isMine });
|
||||
renderChat();
|
||||
}
|
||||
|
||||
function renderChat() {
|
||||
const el = document.getElementById('wp-chat');
|
||||
if (!el) return;
|
||||
el.innerHTML = chatMessages.map(m => `
|
||||
<div class="wc-msg ${m.mine ? 'wc-mine' : ''}">
|
||||
<div class="wc-meta">${escHtml(m.name || '?')} · ${m.time || ''}</div>
|
||||
<div class="wc-bubble">${escHtml(m.body)}</div>
|
||||
</div>`).join('');
|
||||
el.scrollTop = el.scrollHeight;
|
||||
}
|
||||
|
||||
function escHtml(s) {
|
||||
return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||
}
|
||||
|
||||
function sendChatMsg() {
|
||||
const inp = document.getElementById('wp-chat-inp');
|
||||
const body = inp?.value.trim();
|
||||
if (!body) return;
|
||||
inp.value = '';
|
||||
const now = new Date().toLocaleTimeString('tr-TR', { hour:'2-digit', minute:'2-digit' });
|
||||
addChatMsg({ name: WP_ME_NAME, body, time: now }, true);
|
||||
// Broadcast via sync payload (next poll)
|
||||
pendingChatMsg = { name: WP_ME_NAME, body, time: now };
|
||||
}
|
||||
|
||||
let pendingChatMsg = null;
|
||||
|
||||
// ── Party Sync ─────────────────────────────────────────────────
|
||||
function renderMembers(members) {
|
||||
const el = document.getElementById('wp-members');
|
||||
const cnt = document.getElementById('wp-member-count');
|
||||
if (el) el.innerHTML = members.map(m => `
|
||||
<div class="wp-member ${m.is_host ? 'host' : ''}">
|
||||
${m.is_host ? '<i class="bi bi-star-fill" style="font-size:.6rem;color:#ffd700"></i>' : ''}
|
||||
${escHtml(m.name || '?')}
|
||||
</div>`).join('');
|
||||
if (cnt) cnt.textContent = members.length + ' üye aktif';
|
||||
}
|
||||
|
||||
async function doSync() {
|
||||
const body = WP_IS_HOST
|
||||
? { current_sec: Math.floor(vd?.currentTime ?? 0), is_playing: !(vd?.paused ?? true) }
|
||||
: {};
|
||||
|
||||
try {
|
||||
const r = await fetch(`/party/${WP_ROOM}/sync`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': WP_CSRF, 'Accept': 'application/json' },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const d = await r.json();
|
||||
renderMembers(d.members || []);
|
||||
|
||||
// Non-host senkron
|
||||
if (!WP_IS_HOST && vd) {
|
||||
const diff = Math.abs(vd.currentTime - d.current_sec);
|
||||
if (diff > 2) vd.currentTime = d.current_sec;
|
||||
if (d.is_playing && vd.paused) vd.play().catch(()=>{});
|
||||
if (!d.is_playing && !vd.paused) vd.pause();
|
||||
}
|
||||
|
||||
document.getElementById('wp-sync-status').textContent = '✅ senkron ' + new Date().toLocaleTimeString('tr-TR',{hour:'2-digit',minute:'2-digit',second:'2-digit'});
|
||||
pendingChatMsg = null;
|
||||
} catch(e) {
|
||||
document.getElementById('wp-sync-status').textContent = '❌ bağlantı kesildi';
|
||||
}
|
||||
}
|
||||
|
||||
function hostPlay() { if (vd) { vd.play().catch(()=>{}); } }
|
||||
function hostPause() { if (vd) vd.pause(); }
|
||||
|
||||
function copyCode() {
|
||||
navigator.clipboard?.writeText(WP_ROOM).then(() => {
|
||||
if (window.showToast) showToast('Oda kodu kopyalandı: ' + WP_ROOM, 'success');
|
||||
else alert('Oda kodu kopyalandı: ' + WP_ROOM);
|
||||
});
|
||||
}
|
||||
|
||||
// İlk join
|
||||
if (WP_IS_AUTH) {
|
||||
fetch(`/party/${WP_ROOM}/join`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': WP_CSRF, 'Accept': 'application/json' },
|
||||
body: JSON.stringify({}),
|
||||
}).then(r => r.json()).then(d => {
|
||||
if (d.ok) {
|
||||
renderMembers(d.members || []);
|
||||
if (!WP_IS_HOST && vd && d.current_sec > 0) {
|
||||
vd.currentTime = d.current_sec;
|
||||
}
|
||||
}
|
||||
}).catch(()=>{});
|
||||
}
|
||||
|
||||
setInterval(doSync, 3000);
|
||||
|
||||
// Ayrılma temizliği
|
||||
window.addEventListener('beforeunload', () => {
|
||||
navigator.sendBeacon(`/party/${WP_ROOM}/leave`, new Blob([JSON.stringify({})], { type: 'application/json' }));
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
Reference in New Issue
Block a user