Reads resources/data/partners.json (url/anchor/title/rel), cached by the file's mtime so edits go live on the next deploy. Skips invalid/non-http entries and renders nothing when the list is empty. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3469 lines
149 KiB
PHP
3469 lines
149 KiB
PHP
<!DOCTYPE html>
|
||
<html lang="tr" prefix="og: https://ogp.me/ns#">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<meta name="theme-color" content="#06060d">
|
||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||
@php
|
||
// SEO ayarlarını cache'den yükle
|
||
$__seo = cache()->remember('seo_settings', 3600, fn() =>
|
||
\App\Models\Setting::where('key','like','seo_%')->pluck('value','key')->toArray()
|
||
);
|
||
$__seoSite = $__seo['seo_site_name'] ?? 'Animexe';
|
||
$__seoDefDesc = $__seo['seo_home_description'] ?? 'Animexe\'de binlerce anime dizisi ve filmini Türkçe altyazılı veya dublajlı, ücretsiz HD kalitede izleyin.';
|
||
$__seoDefKw = $__seo['seo_home_keywords'] ?? 'anime izle, türkçe anime, anime dizi, anime film, ücretsiz anime';
|
||
$__seoOgImg = url($__seo['seo_og_image'] ?? '/logo.jpg');
|
||
$__seoDomain = rtrim($__seo['seo_canonical_domain'] ?? config('app.url'), '/');
|
||
$__seoCanon = $__seoDomain . '/' . ltrim(request()->path(), '/');
|
||
$__seoTwitter = $__seo['seo_twitter_site'] ?? '';
|
||
$__seoGa = $__seo['seo_google_analytics'] ?? '';
|
||
$__seoGtm = $__seo['seo_gtm_id'] ?? '';
|
||
$__seoGsc = $__seo['seo_gsc_verification'] ?? '';
|
||
$__seoBing = $__seo['seo_bing_verification'] ?? '';
|
||
$__seoYandex = $__seo['seo_yandex_verification'] ?? '';
|
||
$__seoSchema = ($__seo['seo_enable_schema'] ?? '1') === '1';
|
||
// Sayfa başlığı ve diğerleri (child template section'ları okuma)
|
||
$__pageTitle = $__env->yieldContent('title', $__seoSite . ' — Türkçe Anime İzle');
|
||
$__pageDesc = $__env->yieldContent('meta_description', $__seoDefDesc);
|
||
$__pageKw = $__env->yieldContent('meta_keywords', $__seoDefKw);
|
||
$__pageRobots = $__env->yieldContent('robots', 'index, follow');
|
||
$__pageCanon = $__env->yieldContent('canonical', $__seoCanon);
|
||
$__pageOgType = $__env->yieldContent('og_type', 'website');
|
||
$__pageOgTitle = $__env->yieldContent('og_title', $__pageTitle);
|
||
$__pageOgDesc = $__env->yieldContent('og_description', $__pageDesc);
|
||
$__pageOgImg = $__env->yieldContent('og_image', $__seoOgImg);
|
||
$__pageOgImgW = $__env->yieldContent('og_image_width', '1200');
|
||
$__pageOgImgH = $__env->yieldContent('og_image_height', '630');
|
||
@endphp
|
||
{{-- LCP Preload: sayfaya özgü kritik görseller --}}
|
||
@yield('preload')
|
||
<title>{{ $__pageTitle }}</title>
|
||
{{-- Temel Meta --}}
|
||
<meta name="description" content="{{ $__pageDesc }}">
|
||
<meta name="keywords" content="{{ $__pageKw }}">
|
||
<meta name="robots" content="{{ $__pageRobots }}">
|
||
<link rel="canonical" href="{{ $__pageCanon }}">
|
||
<link rel="alternate" hreflang="tr" href="{{ $__pageCanon }}">
|
||
<link rel="alternate" hreflang="x-default" href="{{ $__pageCanon }}">
|
||
@php $__favicon = \App\Models\Setting::get('site_favicon','') @endphp
|
||
@if($__favicon)<link rel="icon" href="{{ $__favicon }}">@else<link rel="icon" href="/favicon.png">@endif
|
||
<link rel="manifest" href="/manifest.json">
|
||
<link rel="search" type="application/opensearchdescription+xml" title="Animexe Anime Ara" href="/opensearch.xml">
|
||
{{-- Preconnect: CDN ve harici kaynaklar --}}
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
|
||
<link rel="dns-prefetch" href="https://www.googletagmanager.com">
|
||
<link rel="dns-prefetch" href="https://www.google-analytics.com">
|
||
{{-- Doğrulama Etiketleri --}}
|
||
@if($__seoGsc)<meta name="google-site-verification" content="{{ $__seoGsc }}">@endif
|
||
@if($__seoBing)<meta name="msvalidate.01" content="{{ $__seoBing }}">@endif
|
||
@if($__seoYandex)<meta name="yandex-verification" content="{{ $__seoYandex }}">@endif
|
||
{{-- Open Graph --}}
|
||
<meta property="og:site_name" content="{{ $__seoSite }}">
|
||
<meta property="og:locale" content="tr_TR">
|
||
<meta property="og:type" content="{{ $__pageOgType }}">
|
||
<meta property="og:title" content="{{ $__pageOgTitle }}">
|
||
<meta property="og:description" content="{{ $__pageOgDesc }}">
|
||
<meta property="og:image" content="{{ $__pageOgImg }}">
|
||
<meta property="og:image:width" content="{{ $__pageOgImgW }}">
|
||
<meta property="og:image:height" content="{{ $__pageOgImgH }}">
|
||
<meta property="og:url" content="{{ $__pageCanon }}">
|
||
@if(!empty($__seo['seo_facebook_app_id']))<meta property="fb:app_id" content="{{ $__seo['seo_facebook_app_id'] }}">@endif
|
||
{{-- Twitter Card --}}
|
||
<meta name="twitter:card" content="summary_large_image">
|
||
@if($__seoTwitter)<meta name="twitter:site" content="{{ Str::startsWith($__seoTwitter,'@') ? $__seoTwitter : '@'.$__seoTwitter }}">@endif
|
||
<meta name="twitter:title" content="{{ $__pageOgTitle }}">
|
||
<meta name="twitter:description" content="{{ $__pageOgDesc }}">
|
||
<meta name="twitter:image" content="{{ $__pageOgImg }}">
|
||
{{-- JSON-LD: WebSite Schema (sitewide) --}}
|
||
@if($__seoSchema)
|
||
<script type="application/ld+json">
|
||
{
|
||
"@@context":"https://schema.org",
|
||
"@@type":"WebSite",
|
||
"name":"{{ $__seoSite }}",
|
||
"url":"{{ $__seoDomain }}",
|
||
"description":"{{ addslashes($__seoDefDesc) }}",
|
||
"inLanguage":"tr-TR",
|
||
"potentialAction":{
|
||
"@@type":"SearchAction",
|
||
"target":{"@@type":"EntryPoint","urlTemplate":"{{ $__seoDomain }}/search?q={search_term_string}"},
|
||
"query-input":"required name=search_term_string"
|
||
}
|
||
}
|
||
</script>
|
||
@if(!empty($__seo['seo_org_logo']) || !empty($__seo['seo_org_twitter']))
|
||
<script type="application/ld+json">
|
||
{
|
||
"@@context":"https://schema.org",
|
||
"@@type":"Organization",
|
||
"name":"{{ $__seoSite }}",
|
||
"url":"{{ $__seoDomain }}",
|
||
"logo":{"@type":"ImageObject","url":"{{ url($__seo['seo_org_logo'] ?? '/logo.jpg') }}"},
|
||
"sameAs":[
|
||
@php $sameAs = array_filter([$__seo['seo_org_twitter'] ?? null, $__seo['seo_org_facebook'] ?? null, $__seo['seo_org_instagram'] ?? null]); @endphp
|
||
@foreach(array_values($sameAs) as $i => $sa)"{{ $sa }}"{{ $i < count($sameAs)-1 ? ',' : '' }}@endforeach
|
||
]
|
||
}
|
||
</script>
|
||
@endif
|
||
@endif
|
||
{{-- Sayfaya özgü JSON-LD --}}
|
||
@yield('schema')
|
||
{{-- Google Analytics 4 --}}
|
||
@if($__seoGtm)
|
||
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','{{ $__seoGtm }}');</script>
|
||
@elseif($__seoGa)
|
||
<script async src="https://www.googletagmanager.com/gtag/js?id={{ $__seoGa }}"></script>
|
||
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());gtag('config','{{ $__seoGa }}');</script>
|
||
@endif
|
||
{{-- Ayris VPS Panel Analytics --}}
|
||
<script defer src="https://panel.ayris.tech/api/analytics/script" data-domain="animexe.com"></script>
|
||
<style>
|
||
/* ── Initial page load splash (inline, no FOUC) ────────────────── */
|
||
#splash{
|
||
position:fixed;inset:0;z-index:99999;
|
||
background:#06060d;
|
||
display:flex;flex-direction:column;align-items:center;justify-content:center;gap:28px;
|
||
transition:opacity .35s ease, visibility .35s ease;
|
||
}
|
||
#splash.done{ opacity:0;visibility:hidden; }
|
||
.splash-logo{
|
||
font-family:'Orbitron','system-ui',sans-serif;
|
||
font-size:clamp(1.6rem,5vw,2.4rem);font-weight:900;
|
||
letter-spacing:.22em;text-transform:uppercase;
|
||
background:linear-gradient(105deg,#fff 0%,#00f5ff 40%,#ff2d7d 100%);
|
||
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;
|
||
text-shadow:none;
|
||
animation:splash-pulse 1.4s ease-in-out infinite alternate;
|
||
}
|
||
@keyframes splash-pulse{
|
||
from{ filter:drop-shadow(0 0 8px rgba(0,245,255,.4)); }
|
||
to{ filter:drop-shadow(0 0 20px rgba(255,45,125,.5)); }
|
||
}
|
||
.splash-bar-wrap{
|
||
width:min(220px,55vw);height:2px;
|
||
background:rgba(255,255,255,.08);border-radius:2px;overflow:hidden;
|
||
}
|
||
.splash-bar{
|
||
height:100%;width:0%;border-radius:2px;
|
||
background:linear-gradient(90deg,#00f5ff,#ff2d7d,#b84dff);
|
||
animation:splash-fill 1.1s cubic-bezier(.4,0,.2,1) forwards;
|
||
}
|
||
@keyframes splash-fill{ to{ width:100%; } }
|
||
.splash-dots{
|
||
display:flex;gap:7px;
|
||
}
|
||
.splash-dots span{
|
||
width:6px;height:6px;border-radius:50%;
|
||
background:#00f5ff;opacity:.25;
|
||
animation:sdot 1s ease-in-out infinite;
|
||
}
|
||
.splash-dots span:nth-child(2){ animation-delay:.18s;background:#ff2d7d; }
|
||
.splash-dots span:nth-child(3){ animation-delay:.36s;background:#b84dff; }
|
||
@keyframes sdot{
|
||
0%,100%{ opacity:.25;transform:scale(1); }
|
||
50%{ opacity:1;transform:scale(1.5); }
|
||
}
|
||
</style>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Orbitron:wght@500;700;800;900&family=Outfit:wght@300;400;500;600;700;800&display=swap">
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
||
<style>
|
||
/* ── Neon cyber theme ─────────────────────────────────────────── */
|
||
:root{
|
||
--bg:#06060d;
|
||
--bg2:#0a0a14;
|
||
--surface:#11111f;
|
||
--surface2:#18182a;
|
||
--border:rgba(0,245,255,.14);
|
||
--border2:rgba(255,45,125,.2);
|
||
--accent:#ff2d7d;
|
||
--accent2:#00f5ff;
|
||
--accent3:#b84dff;
|
||
--glow:rgba(0,245,255,.18);
|
||
--glow-pink:rgba(255,45,125,.25);
|
||
--text:#f0f4ff;
|
||
--text2:#9ca8d4;
|
||
--text3:#5c6789;
|
||
--nav-h:64px;
|
||
--r:10px;
|
||
--r2:14px;
|
||
--font:'Outfit',system-ui,sans-serif;
|
||
--font-display:'Orbitron',sans-serif;
|
||
--shadow-neon:0 0 32px rgba(0,245,255,.12),0 0 64px rgba(255,45,125,.08);
|
||
--shadow-card:0 4px 24px rgba(0,0,0,.45);
|
||
}
|
||
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
||
html{scroll-behavior:smooth;overflow-x:hidden}
|
||
body{
|
||
font-family:var(--font);font-size:15px;line-height:1.6;color:var(--text);
|
||
overflow-x:hidden;min-height:100vh;width:100%;max-width:100vw;
|
||
background-color:var(--bg);
|
||
background-image:
|
||
radial-gradient(ellipse 120% 70% at 50% -25%,rgba(184,77,255,.22),transparent 55%),
|
||
radial-gradient(ellipse 80% 50% at 100% 20%,rgba(0,245,255,.08),transparent 45%),
|
||
radial-gradient(ellipse 70% 45% at 0% 90%,rgba(255,45,125,.1),transparent 50%),
|
||
linear-gradient(180deg,#06060d 0%,#08081a 50%,#06060d 100%);
|
||
}
|
||
body::before{
|
||
content:'';position:fixed;inset:0;pointer-events:none;z-index:0;
|
||
background-image:
|
||
linear-gradient(rgba(0,245,255,.035) 1px,transparent 1px),
|
||
linear-gradient(90deg,rgba(0,245,255,.035) 1px,transparent 1px);
|
||
background-size:56px 56px;
|
||
mask-image:linear-gradient(180deg,rgba(0,0,0,.9) 0%,rgba(0,0,0,.4) 70%,transparent 100%);
|
||
}
|
||
a{color:inherit;text-decoration:none}
|
||
img{max-width:100%;display:block}
|
||
button,input,select{font-family:inherit}
|
||
::-webkit-scrollbar{width:8px;height:8px}
|
||
::-webkit-scrollbar-track{background:rgba(0,0,0,.2)}
|
||
::-webkit-scrollbar-thumb{
|
||
background:linear-gradient(180deg,rgba(0,245,255,.35),rgba(255,45,125,.35));
|
||
border-radius:8px;
|
||
}
|
||
|
||
/* ── Navbar ───────────────────────────────────────────────────── */
|
||
#topnav{
|
||
position:fixed;top:0;left:0;right:0;z-index:500;
|
||
height:var(--nav-h);
|
||
display:flex;align-items:center;gap:10px;
|
||
padding:0 22px;
|
||
background:rgba(6,6,13,.82);
|
||
backdrop-filter:blur(16px) saturate(1.2);
|
||
border-bottom:1px solid var(--border);
|
||
box-shadow:0 4px 30px rgba(0,0,0,.35),0 0 40px rgba(0,245,255,.04);
|
||
}
|
||
#topnav::after{
|
||
content:'';position:absolute;bottom:0;left:0;right:0;height:1px;
|
||
background:linear-gradient(90deg,transparent,var(--accent2),var(--accent),transparent);
|
||
opacity:.45;pointer-events:none;
|
||
}
|
||
.nav-logo{
|
||
font-family:var(--font-display);
|
||
font-size:1.05rem;font-weight:800;letter-spacing:.18em;
|
||
text-transform:uppercase;
|
||
color:var(--text);
|
||
text-shadow:0 0 24px rgba(0,245,255,.5),0 0 40px rgba(255,45,125,.35);
|
||
flex-shrink:0;margin-right:12px;
|
||
background:linear-gradient(105deg,#fff 0%,var(--accent2) 40%,var(--accent) 100%);
|
||
-webkit-background-clip:text;-webkit-text-fill-color:transparent;
|
||
background-clip:text;
|
||
}
|
||
.nav-links{display:flex;gap:4px;list-style:none}
|
||
.nav-links a{
|
||
padding:8px 14px;border-radius:var(--r);font-size:.86rem;font-weight:600;
|
||
color:var(--text2);transition:all .18s;
|
||
border:1px solid transparent;
|
||
}
|
||
.nav-links a:hover{
|
||
color:var(--accent2);
|
||
background:rgba(0,245,255,.06);
|
||
border-color:rgba(0,245,255,.2);
|
||
box-shadow:0 0 20px rgba(0,245,255,.1);
|
||
}
|
||
.nav-links a.on{
|
||
color:var(--text);
|
||
background:rgba(255,45,125,.1);
|
||
border-color:rgba(255,45,125,.35);
|
||
box-shadow:0 0 24px rgba(255,45,125,.15);
|
||
}
|
||
.nav-search{margin-left:auto;display:flex;align-items:center;gap:10px}
|
||
.ns-form{position:relative;display:flex;align-items:center}
|
||
.ns-form input{
|
||
background:rgba(17,17,31,.9);border:1px solid var(--border);border-radius:999px;
|
||
padding:9px 16px 9px 38px;color:var(--text);font-size:.85rem;
|
||
width:210px;outline:none;transition:all .22s;
|
||
}
|
||
.ns-form input:focus{
|
||
width:280px;border-color:var(--accent2);
|
||
background:rgba(0,245,255,.06);
|
||
box-shadow:0 0 0 2px rgba(0,245,255,.2),0 0 28px rgba(0,245,255,.12);
|
||
}
|
||
.ns-form input::placeholder{color:var(--text3)}
|
||
.ns-form .ns-icon{position:absolute;left:13px;color:var(--accent2);font-size:.92rem;pointer-events:none;opacity:.85}
|
||
/* ── Autocomplete dropdown ────────────────────────── */
|
||
.ns-ac{
|
||
position:absolute;top:calc(100% + 6px);left:0;right:0;
|
||
background:#0d0d1c;border:1px solid rgba(0,245,255,.22);
|
||
border-radius:14px;overflow:hidden;
|
||
box-shadow:0 16px 48px rgba(0,0,0,.7),0 0 0 1px rgba(0,245,255,.06);
|
||
z-index:9999;display:none;min-width:320px;
|
||
}
|
||
.ns-ac.show{display:block;animation:acIn .16s ease}
|
||
@keyframes acIn{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
|
||
.ns-ac-item{
|
||
display:flex;align-items:center;gap:11px;padding:9px 14px;
|
||
cursor:pointer;transition:background .12s;text-decoration:none;
|
||
}
|
||
.ns-ac-item:hover,.ns-ac-item.focused{background:rgba(0,245,255,.07)}
|
||
.ns-ac-item img,.ns-ac-item .ns-ac-ph{
|
||
width:34px;height:48px;border-radius:5px;object-fit:cover;flex-shrink:0;
|
||
}
|
||
.ns-ac-ph{background:rgba(255,255,255,.07);display:flex;align-items:center;justify-content:center}
|
||
.ns-ac-info{flex:1;min-width:0}
|
||
.ns-ac-title{color:var(--text);font-size:.83rem;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||
.ns-ac-meta{color:var(--text3);font-size:.72rem;margin-top:2px}
|
||
.ns-ac-type{
|
||
font-size:.65rem;font-weight:800;padding:2px 7px;border-radius:4px;
|
||
background:rgba(0,245,255,.1);color:var(--accent2);border:1px solid rgba(0,245,255,.2);flex-shrink:0;
|
||
}
|
||
.ns-ac-all{
|
||
display:block;text-align:center;padding:9px;
|
||
font-size:.78rem;color:var(--accent2);font-weight:700;
|
||
border-top:1px solid rgba(255,255,255,.06);
|
||
transition:background .12s;
|
||
}
|
||
.ns-ac-all:hover{background:rgba(0,245,255,.06)}
|
||
.nav-auth{display:flex;gap:10px;align-items:center;flex-shrink:0}
|
||
.btn-ghost{
|
||
background:rgba(17,17,31,.6);border:1px solid rgba(0,245,255,.28);color:var(--text2);
|
||
padding:8px 18px;border-radius:999px;font-size:.82rem;font-weight:600;cursor:pointer;
|
||
transition:all .18s;
|
||
}
|
||
.btn-ghost:hover{
|
||
border-color:var(--accent2);color:var(--accent2);
|
||
box-shadow:0 0 20px rgba(0,245,255,.2);
|
||
}
|
||
.btn-solid{
|
||
background:linear-gradient(135deg,var(--accent) 0%,var(--accent3) 100%);
|
||
color:#fff;border:none;
|
||
padding:8px 20px;border-radius:999px;font-size:.82rem;font-weight:700;cursor:pointer;
|
||
transition:transform .16s,box-shadow .2s;
|
||
box-shadow:0 0 24px rgba(255,45,125,.35),0 4px 16px rgba(184,77,255,.2);
|
||
}
|
||
.btn-solid:hover{transform:translateY(-1px);box-shadow:0 0 32px rgba(255,45,125,.5)}
|
||
.nav-bell{position:relative;display:flex;align-items:center;justify-content:center;width:36px;height:36px;border-radius:50%;color:var(--text2);text-decoration:none;font-size:1.1rem;transition:color .15s,background .15s}
|
||
.nav-bell:hover{color:var(--accent2);background:rgba(0,245,255,.08)}
|
||
.bell-badge{position:absolute;top:2px;right:2px;min-width:16px;height:16px;border-radius:8px;background:var(--accent);color:#fff;font-size:.6rem;font-weight:800;display:flex;align-items:center;justify-content:center;padding:0 3px;pointer-events:none}
|
||
.nav-user{position:relative;display:flex;align-items:center;gap:8px;cursor:pointer}
|
||
.nav-avatar{
|
||
width:34px;height:34px;border-radius:50%;
|
||
background:linear-gradient(135deg,var(--accent2),var(--accent));
|
||
display:flex;align-items:center;justify-content:center;
|
||
font-size:.78rem;font-weight:800;color:#06060d;flex-shrink:0;
|
||
box-shadow:0 0 16px rgba(0,245,255,.4);
|
||
}
|
||
.nav-user-name{font-size:.82rem;font-weight:600;max-width:100px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||
.nav-dropdown{
|
||
position:absolute;top:100%;right:0;
|
||
background:rgba(10,10,20,.96);border:1px solid var(--border);border-radius:var(--r2);
|
||
padding:20px 8px 8px;min-width:180px;display:none;z-index:200;
|
||
box-shadow:var(--shadow-neon),0 16px 48px rgba(0,0,0,.55);
|
||
margin-top:0;
|
||
}
|
||
.nav-user:hover .nav-dropdown{display:block}
|
||
.nav-dropdown a,.nav-dropdown button{
|
||
display:flex;align-items:center;gap:8px;width:100%;
|
||
padding:10px 12px;border-radius:var(--r);color:var(--text2);font-size:.85rem;font-weight:500;
|
||
background:none;border:none;cursor:pointer;transition:all .14s;text-align:left;
|
||
}
|
||
.nav-dropdown a:hover,.nav-dropdown button:hover{
|
||
background:rgba(0,245,255,.08);color:var(--accent2);
|
||
}
|
||
.nav-dropdown .sep{height:1px;background:linear-gradient(90deg,transparent,var(--border),transparent);margin:6px 0}
|
||
.nav-ham{display:none;background:none;border:none;color:var(--accent2);font-size:1.45rem;cursor:pointer;margin-left:auto;padding:6px;filter:drop-shadow(0 0 8px rgba(0,245,255,.4))}
|
||
|
||
#mob-menu{
|
||
display:none;flex-direction:column;
|
||
position:fixed;top:var(--nav-h);left:0;right:0;
|
||
background:rgba(6,6,14,.98);backdrop-filter:blur(20px) saturate(1.4);
|
||
border-bottom:1px solid var(--border);
|
||
padding:0 0 16px;z-index:499;gap:0;
|
||
box-shadow:0 20px 60px rgba(0,0,0,.6),0 0 40px rgba(0,245,255,.04);
|
||
max-height:calc(100vh - var(--nav-h));
|
||
overflow-y:auto;
|
||
}
|
||
#mob-menu::before{
|
||
content:'';display:block;height:1px;
|
||
background:linear-gradient(90deg,transparent,var(--accent2),var(--accent),transparent);
|
||
opacity:.4;flex-shrink:0;
|
||
}
|
||
#mob-menu.open{display:flex}
|
||
.mob-nav-links{padding:10px 14px 6px;display:flex;flex-direction:column;gap:2px}
|
||
#mob-menu a{
|
||
padding:12px 16px;border-radius:var(--r);color:var(--text2);font-weight:600;transition:all .14s;
|
||
border:1px solid transparent;display:flex;align-items:center;gap:10px;
|
||
}
|
||
#mob-menu a:hover{background:rgba(0,245,255,.08);border-color:rgba(0,245,255,.18);color:var(--accent2)}
|
||
#mob-menu a i{font-size:1rem;opacity:.7;width:18px;text-align:center}
|
||
.mob-divider{height:1px;background:linear-gradient(90deg,transparent,var(--border),transparent);margin:8px 14px}
|
||
.mob-search{padding:0 14px 8px;position:relative}
|
||
.mob-search input{
|
||
width:100%;background:var(--surface);border:1px solid var(--border);
|
||
border-radius:var(--r);padding:12px 16px 12px 42px;color:var(--text);font-size:.9rem;outline:none;
|
||
transition:border-color .18s;
|
||
}
|
||
.mob-search input:focus{border-color:var(--accent2);box-shadow:0 0 0 2px rgba(0,245,255,.15)}
|
||
.mob-search .ns-icon{position:absolute;left:27px;top:50%;transform:translateY(-50%);color:var(--accent2);pointer-events:none}
|
||
.mob-auth{display:flex;gap:10px;padding:6px 14px;margin-top:4px}
|
||
.mob-auth a{flex:1;text-align:center;padding:13px;border-radius:var(--r);font-size:.86rem;font-weight:700;display:flex;align-items:center;justify-content:center;gap:7px}
|
||
.mob-auth .login{background:var(--surface);color:var(--text2);border:1px solid var(--border)}
|
||
.mob-auth .login:hover{border-color:var(--accent2);color:var(--accent2)}
|
||
.mob-auth .reg{background:linear-gradient(135deg,var(--accent),var(--accent3));color:#fff;box-shadow:0 0 20px rgba(255,45,125,.3)}
|
||
.mob-user-block{padding:16px 14px 10px;display:flex;align-items:center;gap:13px;border-bottom:1px solid rgba(0,245,255,.08);margin-bottom:4px}
|
||
.mob-user-ava{
|
||
width:42px;height:42px;border-radius:50%;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:#06060d;
|
||
box-shadow:0 0 18px rgba(0,245,255,.4);
|
||
}
|
||
.mob-user-info{flex:1;min-width:0}
|
||
.mob-user-name{font-size:.9rem;font-weight:700;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||
.mob-user-tier{font-size:.72rem;color:var(--text3);margin-top:1px}
|
||
|
||
#pg{padding-top:var(--nav-h);min-height:100vh;position:relative;z-index:1;overflow-x:hidden;max-width:100%}
|
||
|
||
.section{padding:40px 28px;max-width:1680px;margin:0 auto}
|
||
.section-hdr{display:flex;align-items:center;justify-content:space-between;margin-bottom:26px}
|
||
.section-title{
|
||
font-family:var(--font-display);
|
||
font-size:clamp(1.0rem,1.8vw,1.3rem);font-weight:900;letter-spacing:.07em;text-transform:uppercase;
|
||
display:flex;align-items:center;gap:13px;color:var(--text);
|
||
}
|
||
.section-title::before{
|
||
content:'';width:4px;height:26px;
|
||
background:linear-gradient(180deg,var(--accent2),var(--accent));
|
||
border-radius:3px;
|
||
box-shadow:0 0 16px rgba(0,245,255,.7),0 0 24px rgba(255,45,125,.45);
|
||
}
|
||
.section-more{
|
||
color:var(--accent2);font-size:.82rem;font-weight:700;letter-spacing:.04em;
|
||
text-transform:uppercase;
|
||
padding:7px 14px;border-radius:8px;border:1px solid rgba(0,245,255,.3);
|
||
background:rgba(0,245,255,.04);
|
||
transition:all .18s;
|
||
}
|
||
.section-more:hover{
|
||
background:rgba(0,245,255,.1);box-shadow:0 0 20px rgba(0,245,255,.2);
|
||
text-decoration:none;
|
||
}
|
||
|
||
.a-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:20px}
|
||
.a-card{
|
||
background:linear-gradient(145deg,rgba(17,17,31,.96),rgba(10,10,20,.99));
|
||
border-radius:14px;overflow:hidden;cursor:pointer;
|
||
border:1px solid rgba(255,255,255,.07);
|
||
transition:transform .22s,box-shadow .25s,border-color .22s;
|
||
box-shadow:0 6px 28px rgba(0,0,0,.5);
|
||
}
|
||
.a-card:hover{
|
||
transform:translateY(-7px) scale(1.01);
|
||
border-color:rgba(255,45,125,.48);
|
||
box-shadow:0 20px 56px rgba(0,0,0,.6),0 0 44px rgba(255,45,125,.12),0 0 64px rgba(0,245,255,.06);
|
||
}
|
||
.a-poster{position:relative;aspect-ratio:2/3;background:var(--surface2);overflow:hidden}
|
||
.a-poster::after{
|
||
content:'';position:absolute;inset:0;pointer-events:none;
|
||
box-shadow:inset 0 0 40px rgba(0,0,0,.3);
|
||
}
|
||
/* Shine sweep on hover */
|
||
.a-poster::before{
|
||
content:'';position:absolute;inset:0;z-index:3;pointer-events:none;
|
||
background:linear-gradient(115deg,transparent 35%,rgba(255,255,255,.09) 50%,transparent 65%);
|
||
transform:translateX(-100%) skewX(-15deg);
|
||
transition:transform .65s ease;
|
||
}
|
||
.a-card:hover .a-poster::before{transform:translateX(200%) skewX(-15deg)}
|
||
.a-poster img{width:100%;height:100%;object-fit:cover;transition:transform .35s}
|
||
.a-card:hover .a-poster img{transform:scale(1.08)}
|
||
.a-no-img{width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:var(--text3);font-size:2.5rem}
|
||
.a-badge{
|
||
position:absolute;top:9px;left:9px;
|
||
background:linear-gradient(135deg,var(--accent),var(--accent3));
|
||
color:#fff;font-size:.6rem;font-weight:900;padding:4px 9px;border-radius:5px;
|
||
text-transform:uppercase;letter-spacing:.08em;
|
||
box-shadow:0 0 16px rgba(255,45,125,.5);
|
||
z-index:2;
|
||
}
|
||
.a-rating{
|
||
position:absolute;top:9px;right:9px;background:rgba(6,6,13,.88);
|
||
color:#ffd60a;font-size:.68rem;font-weight:800;padding:4px 8px;border-radius:6px;
|
||
display:flex;align-items:center;gap:3px;backdrop-filter:blur(8px);
|
||
border:1px solid rgba(255,214,10,.25);
|
||
z-index:2;
|
||
}
|
||
.a-hover-play{position:absolute;inset:0;background:rgba(6,6,13,.52);display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .22s;z-index:2}
|
||
.a-card:hover .a-hover-play{opacity:1}
|
||
.play-circle{
|
||
width:52px;height:52px;border-radius:50%;
|
||
background:rgba(255,255,255,.14);backdrop-filter:blur(10px);
|
||
border:2px solid rgba(255,255,255,.55);
|
||
display:flex;align-items:center;justify-content:center;color:#fff;font-size:1.1rem;
|
||
box-shadow:0 0 28px rgba(0,0,0,.5);
|
||
}
|
||
.a-info{padding:13px 13px}
|
||
.a-title{font-size:.88rem;font-weight:700;color:var(--text);line-height:1.35;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
|
||
.a-meta{font-size:.73rem;color:var(--text3);margin-top:5px}
|
||
|
||
.h-row{display:flex;gap:14px;overflow-x:auto;padding:4px 0 12px;scrollbar-width:none}
|
||
.h-row::-webkit-scrollbar{display:none}
|
||
.h-row .a-card{flex-shrink:0;width:152px}
|
||
|
||
.ep-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:14px}
|
||
.ep-card{
|
||
background:linear-gradient(145deg,rgba(17,17,31,.95),rgba(10,10,20,.98));
|
||
border-radius:var(--r2);overflow:hidden;cursor:pointer;border:1px solid rgba(0,245,255,.1);
|
||
transition:transform .2s,box-shadow .22s,border-color .2s;
|
||
}
|
||
.ep-card:hover{
|
||
transform:translateY(-4px);
|
||
border-color:rgba(0,245,255,.35);
|
||
box-shadow:0 12px 36px rgba(0,0,0,.5),0 0 30px rgba(0,245,255,.1);
|
||
}
|
||
.ep-thumb{position:relative;aspect-ratio:16/9;background:var(--surface2);overflow:hidden}
|
||
.ep-thumb img{width:100%;height:100%;object-fit:cover;transition:transform .28s}
|
||
.ep-card:hover .ep-thumb img{transform:scale(1.05)}
|
||
.ep-ep-badge{
|
||
position:absolute;bottom:8px;left:8px;
|
||
background:linear-gradient(135deg,var(--accent2),var(--accent));
|
||
color:#06060d;font-size:.65rem;font-weight:900;padding:3px 9px;border-radius:6px;
|
||
box-shadow:0 0 16px rgba(0,245,255,.4);
|
||
}
|
||
.ep-play{position:absolute;inset:0;background:rgba(6,6,13,.45);display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s}
|
||
.ep-card:hover .ep-play{opacity:1}
|
||
.ep-body{padding:10px 12px}
|
||
.ep-anime-name{font-size:.7rem;color:var(--accent2);font-weight:700;margin-bottom:3px}
|
||
.ep-title{font-size:.82rem;font-weight:700;color:var(--text);display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden}
|
||
.ep-time{font-size:.72rem;color:var(--text3);margin-top:4px}
|
||
|
||
.genre-chip{
|
||
display:inline-flex;align-items:center;gap:5px;padding:6px 14px;border-radius:999px;
|
||
background:rgba(17,17,31,.8);border:1px solid var(--border);color:var(--text2);
|
||
font-size:.78rem;font-weight:600;transition:all .16s;cursor:pointer;
|
||
}
|
||
.genre-chip:hover,.genre-chip.on{
|
||
background:rgba(255,45,125,.12);border-color:var(--accent);color:var(--accent);
|
||
box-shadow:0 0 20px rgba(255,45,125,.2);
|
||
}
|
||
|
||
.pager{display:flex;justify-content:center;gap:8px;margin-top:36px;flex-wrap:wrap}
|
||
.pager a,.pager span{
|
||
padding:8px 14px;border-radius:var(--r);font-size:.84rem;font-weight:700;
|
||
background:var(--surface);border:1px solid var(--border);color:var(--text2);transition:all .15s;
|
||
}
|
||
.pager a:hover{background:rgba(0,245,255,.08);border-color:var(--accent2);color:var(--accent2)}
|
||
.pager .on{
|
||
background:linear-gradient(135deg,var(--accent),var(--accent3));
|
||
border-color:transparent;color:#fff;
|
||
box-shadow:0 0 20px rgba(255,45,125,.35);
|
||
}
|
||
|
||
.alert{padding:12px 18px;border-radius:var(--r);font-size:.88rem;font-weight:600;margin-bottom:16px}
|
||
.alert-err{background:rgba(255,60,90,.1);border:1px solid rgba(255,60,90,.35);color:#ff8a9a;box-shadow:0 0 20px rgba(255,60,90,.08)}
|
||
.alert-ok{background:rgba(0,245,180,.08);border:1px solid rgba(0,245,180,.3);color:#6effd0}
|
||
|
||
footer{
|
||
position:relative;z-index:1;
|
||
background:linear-gradient(180deg,rgba(6,6,16,.99),#030309);
|
||
border-top:1px solid rgba(255,255,255,.05);
|
||
padding:clamp(40px,5vw,60px) clamp(16px,4vw,40px) clamp(24px,3vw,36px);
|
||
margin-top:56px;
|
||
box-shadow:0 -20px 60px rgba(0,0,0,.4);
|
||
overflow:hidden;
|
||
}
|
||
footer::before{
|
||
content:'';position:absolute;top:0;left:5%;right:5%;height:1px;
|
||
background:linear-gradient(90deg,transparent,var(--accent2),var(--accent),transparent);
|
||
opacity:.55;
|
||
}
|
||
/* Footer ambient glow */
|
||
footer::after{
|
||
content:'';position:absolute;top:-40%;left:50%;transform:translateX(-50%);
|
||
width:600px;height:300px;border-radius:50%;
|
||
background:radial-gradient(ellipse,rgba(0,245,255,.03),transparent 70%);
|
||
pointer-events:none;
|
||
}
|
||
.footer-in{max-width:1200px;margin:0 auto;display:flex;gap:40px;flex-wrap:wrap;justify-content:space-between}
|
||
.footer-brand .logo{
|
||
font-family:var(--font-display);font-size:1.15rem;font-weight:800;letter-spacing:.2em;
|
||
background:linear-gradient(105deg,#fff,var(--accent2),var(--accent));
|
||
-webkit-background-clip:text;-webkit-text-fill-color:transparent;margin-bottom:10px;
|
||
}
|
||
.footer-brand p{color:var(--text3);font-size:.84rem;max-width:280px;line-height:1.65}
|
||
.footer-col h5{
|
||
font-family:var(--font-display);font-size:.68rem;text-transform:uppercase;letter-spacing:.15em;
|
||
color:var(--accent2);font-weight:700;margin-bottom:12px;opacity:.9;
|
||
}
|
||
.footer-col ul{list-style:none;display:flex;flex-direction:column;gap:9px}
|
||
.footer-col a{color:rgba(255,255,255,.35);font-size:.84rem;font-weight:500;transition:all .16s;padding:2px 0;position:relative}
|
||
.footer-col a::after{content:'';position:absolute;bottom:0;left:0;width:0;height:1px;background:var(--accent2);transition:width .2s ease}
|
||
.footer-col a:hover{color:var(--accent2);text-shadow:0 0 14px rgba(0,245,255,.4)}
|
||
.footer-col a:hover::after{width:100%}
|
||
.footer-bottom{
|
||
max-width:1200px;margin:28px auto 0;padding-top:20px;
|
||
border-top:1px solid rgba(0,245,255,.08);
|
||
display:flex;justify-content:space-between;flex-wrap:wrap;gap:10px;color:var(--text3);font-size:.78rem;
|
||
}
|
||
|
||
/* ── Responsive ───────────────────────────────────────────────── */
|
||
@media(max-width:900px){
|
||
#topnav{padding:0 16px}
|
||
.nav-links,.nav-search,.nav-auth{display:none}
|
||
.nav-ham{display:block}
|
||
.section{padding:24px 14px}
|
||
.a-grid{grid-template-columns:repeat(auto-fill,minmax(130px,1fr));gap:12px}
|
||
.h-row .a-card{width:130px}
|
||
}
|
||
@media(max-width:480px){
|
||
.a-grid{grid-template-columns:repeat(3,1fr);gap:9px}
|
||
.ep-grid{grid-template-columns:repeat(2,1fr);gap:9px}
|
||
}
|
||
|
||
/* ═══════════════════════════════════════════════════════
|
||
PREMIUM GLOBAL ENHANCEMENTS v2
|
||
═══════════════════════════════════════════════════════ */
|
||
|
||
/* ── Scroll Progress Bar ────────────────────────────── */
|
||
#scroll-progress{
|
||
position:fixed;top:0;left:0;height:2px;width:0%;z-index:10000;
|
||
background:linear-gradient(90deg,var(--accent2),var(--accent),var(--accent3));
|
||
box-shadow:0 0 10px rgba(0,245,255,.9),0 0 24px rgba(255,45,125,.6);
|
||
transition:width .08s linear;pointer-events:none;
|
||
}
|
||
|
||
/* ── Scroll To Top ──────────────────────────────────── */
|
||
#scroll-top{
|
||
position:fixed;bottom:84px;right:18px;z-index:850;
|
||
width:40px;height:40px;border-radius:50%;background:rgba(6,6,13,.92);
|
||
border:1px solid rgba(0,245,255,.3);color:var(--accent2);font-size:1rem;
|
||
cursor:pointer;display:flex;align-items:center;justify-content:center;
|
||
opacity:0;visibility:hidden;transform:translateY(10px);
|
||
transition:all .26s cubic-bezier(.22,1,.36,1);
|
||
backdrop-filter:blur(14px);
|
||
box-shadow:0 4px 20px rgba(0,0,0,.45),0 0 16px rgba(0,245,255,.1);
|
||
}
|
||
#scroll-top.show{opacity:1;visibility:visible;transform:none}
|
||
#scroll-top:hover{
|
||
background:rgba(0,245,255,.15);border-color:var(--accent2);
|
||
box-shadow:0 0 26px rgba(0,245,255,.4),0 4px 20px rgba(0,0,0,.4);
|
||
transform:translateY(-3px);
|
||
}
|
||
|
||
/* ── Scroll Reveal System ───────────────────────────── */
|
||
.reveal{
|
||
opacity:0;transform:translateY(30px);
|
||
transition:opacity .65s cubic-bezier(.22,1,.36,1),transform .65s cubic-bezier(.22,1,.36,1);
|
||
}
|
||
.reveal.visible{opacity:1;transform:none}
|
||
.reveal-d1{transition-delay:.07s}
|
||
.reveal-d2{transition-delay:.14s}
|
||
.reveal-d3{transition-delay:.21s}
|
||
.reveal-d4{transition-delay:.28s}
|
||
.reveal-d5{transition-delay:.35s}
|
||
|
||
/* Card shine effects are defined per-page */
|
||
|
||
/* ── Navbar Scroll State ────────────────────────────── */
|
||
#topnav{transition:background .3s ease,box-shadow .3s ease,height .25s ease,transform .28s cubic-bezier(.22,1,.36,1)}
|
||
#topnav.scrolled{
|
||
background:rgba(3,3,9,.97)!important;
|
||
box-shadow:0 2px 48px rgba(0,0,0,.65),0 0 60px rgba(0,245,255,.02)!important;
|
||
height:56px;
|
||
}
|
||
#topnav.scrolled .nav-logo{font-size:.92rem}
|
||
|
||
/* ── Ambient Floating Orbs ──────────────────────────── */
|
||
.amb{position:fixed;border-radius:50%;pointer-events:none;z-index:0;filter:blur(90px);will-change:transform}
|
||
.amb-1{
|
||
width:clamp(220px,28vw,420px);height:clamp(220px,28vw,420px);
|
||
background:radial-gradient(circle,rgba(0,245,255,.11),transparent 70%);
|
||
top:-5%;right:0%;
|
||
animation:amb-drift-a 20s ease-in-out infinite alternate;
|
||
}
|
||
.amb-2{
|
||
width:clamp(180px,22vw,340px);height:clamp(180px,22vw,340px);
|
||
background:radial-gradient(circle,rgba(255,45,125,.09),transparent 70%);
|
||
bottom:15%;left:-5%;
|
||
animation:amb-drift-b 25s ease-in-out infinite alternate;
|
||
}
|
||
.amb-3{
|
||
width:clamp(140px,18vw,280px);height:clamp(140px,18vw,280px);
|
||
background:radial-gradient(circle,rgba(184,77,255,.08),transparent 70%);
|
||
top:45%;right:15%;
|
||
animation:amb-drift-c 18s ease-in-out infinite alternate;
|
||
}
|
||
@keyframes amb-drift-a{from{transform:translate(0,0) scale(1)}to{transform:translate(-50px,70px) scale(1.1)}}
|
||
@keyframes amb-drift-b{from{transform:translate(0,0) scale(1)}to{transform:translate(60px,-50px) scale(1.12)}}
|
||
@keyframes amb-drift-c{from{transform:translate(0,0) scale(1)}to{transform:translate(-35px,55px) scale(1.08)}}
|
||
|
||
/* ── Mobile Bottom Navigation ───────────────────────── */
|
||
#mob-bottom-nav{
|
||
display:none;
|
||
position:fixed;bottom:0;left:0;right:0;z-index:490;
|
||
transition:transform .28s cubic-bezier(.22,1,.36,1),opacity .22s;
|
||
height:60px;
|
||
background:rgba(4,4,11,.96);
|
||
backdrop-filter:blur(28px) saturate(1.8);
|
||
border-top:1px solid rgba(255,255,255,.07);
|
||
box-shadow:0 -8px 48px rgba(0,0,0,.65),0 -4px 20px rgba(0,245,255,.03);
|
||
padding-bottom:env(safe-area-inset-bottom,0px);
|
||
}
|
||
#mob-bottom-nav::before{
|
||
content:'';position:absolute;top:0;left:8%;right:8%;height:1px;
|
||
background:linear-gradient(90deg,transparent,rgba(0,245,255,.5),rgba(255,45,125,.4),transparent);
|
||
opacity:.6;
|
||
}
|
||
.mbn-list{
|
||
display:flex;
|
||
width:100%;
|
||
height:60px;
|
||
list-style:none;
|
||
align-items:stretch;
|
||
margin:0;padding:0;
|
||
}
|
||
.mbn-list li{flex:1;display:flex;min-width:0}
|
||
.mbn-a{
|
||
flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
|
||
gap:3px;padding:6px 4px;
|
||
color:rgba(255,255,255,.28);text-decoration:none;
|
||
font-size:.54rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
|
||
position:relative;transition:color .18s;
|
||
-webkit-tap-highlight-color:transparent;
|
||
user-select:none;
|
||
min-width:0;
|
||
overflow:hidden;
|
||
white-space:nowrap;
|
||
}
|
||
.mbn-a i{
|
||
font-size:1.18rem;
|
||
transition:transform .22s cubic-bezier(.34,1.56,.64,1),filter .22s,opacity .18s;
|
||
}
|
||
.mbn-a:active i{transform:scale(.82)!important}
|
||
.mbn-a.on{color:var(--accent2)}
|
||
.mbn-a.on i{
|
||
transform:scale(1.08);
|
||
filter:drop-shadow(0 0 6px rgba(0,245,255,.85));
|
||
}
|
||
.mbn-a.on::after{
|
||
content:'';position:absolute;top:0;left:18%;right:18%;height:2px;
|
||
background:linear-gradient(90deg,var(--accent2),var(--accent));
|
||
border-radius:0 0 4px 4px;
|
||
box-shadow:0 0 10px rgba(0,245,255,.7);
|
||
}
|
||
.mbn-a.mbn-ai.on{color:var(--accent3)!important}
|
||
.mbn-a.mbn-ai.on i{filter:drop-shadow(0 0 6px rgba(184,77,255,.85))!important}
|
||
.mbn-a.mbn-ai.on::after{background:linear-gradient(90deg,var(--accent3),var(--accent))!important;box-shadow:0 0 10px rgba(184,77,255,.7)!important}
|
||
|
||
@media(max-width:900px){
|
||
#mob-bottom-nav{display:flex;flex-direction:column}
|
||
#pg{padding-bottom:calc(60px + env(safe-area-inset-bottom,0px))!important}
|
||
footer{margin-bottom:0}
|
||
#ai-fab{bottom:calc(72px + env(safe-area-inset-bottom,0px))!important;right:14px!important}
|
||
#ai-panel{bottom:calc(136px + env(safe-area-inset-bottom,0px))!important;right:8px!important;left:8px!important;width:auto!important}
|
||
#scroll-top{bottom:calc(138px + env(safe-area-inset-bottom,0px));right:14px;width:36px;height:36px;font-size:.88rem}
|
||
}
|
||
@media(max-width:480px){
|
||
.mbn-a{font-size:.5rem}
|
||
.mbn-a i{font-size:1.12rem}
|
||
}
|
||
|
||
/* ── Enhanced Genre Cards ───────────────────────────── */
|
||
.gc{overflow:hidden;position:relative}
|
||
.gc::after{
|
||
content:'';position:absolute;inset:0;
|
||
background:radial-gradient(ellipse at 10% 90%,var(--gc,#00f5ff) 0%,transparent 60%);
|
||
opacity:0;transition:opacity .28s;
|
||
}
|
||
.gc:hover::after{opacity:.1}
|
||
|
||
/* ── Home Section Headers Enhanced ─────────────────── */
|
||
.hs-hdr{position:relative}
|
||
|
||
/* ── Promo Banner Glow Pulse ────────────────────────── */
|
||
@keyframes promo-pulse{
|
||
0%,100%{transform:translate(-10%,-20%) scale(1);opacity:.6}
|
||
50%{transform:translate(15%,15%) scale(1.25);opacity:.25}
|
||
}
|
||
.promo-inner{overflow:hidden}
|
||
.promo-inner::after{
|
||
content:'';position:absolute;
|
||
width:320px;height:320px;border-radius:50%;
|
||
background:radial-gradient(circle,rgba(0,245,255,.07),transparent);
|
||
top:-80px;right:8%;
|
||
animation:promo-pulse 7s ease-in-out infinite;pointer-events:none;
|
||
}
|
||
|
||
/* ── Ticker glow on hover ───────────────────────────── */
|
||
.ticker-item a{transition:color .15s,text-shadow .15s}
|
||
.ticker-item a:hover{color:var(--accent2);text-shadow:0 0 14px rgba(0,245,255,.55)}
|
||
|
||
/* ── Footer glow line ───────────────────────────────── */
|
||
footer{position:relative}
|
||
|
||
/* ── Card hover micro-interaction enhancement ───────── */
|
||
.a-card:hover,.ep-card:hover{
|
||
border-color:rgba(255,45,125,.5);
|
||
}
|
||
|
||
/* ── Splash screen improvement ──────────────────────── */
|
||
.splash-logo{animation:splash-pulse 1.2s ease-in-out infinite alternate}
|
||
|
||
/* ── Bottom nav APK banner spacing ─────────────────── */
|
||
@media(max-width:900px){
|
||
.app-download-banner{margin-bottom:8px}
|
||
}
|
||
|
||
/* ── Custom scrollbar (webkit) enhancement ─────────── */
|
||
::-webkit-scrollbar-thumb:hover{
|
||
background:linear-gradient(180deg,rgba(0,245,255,.6),rgba(255,45,125,.6));
|
||
}
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
CHAT PANEL v2
|
||
════════════════════════════════════════════════════ */
|
||
#cp-backdrop{
|
||
display:none;position:fixed;inset:0;z-index:900;
|
||
background:rgba(0,0,0,.55);backdrop-filter:blur(4px);
|
||
}
|
||
#cp-backdrop.on{display:block}
|
||
|
||
#chat-panel{
|
||
position:fixed;top:0;right:0;bottom:0;z-index:901;
|
||
width:420px;max-width:100vw;
|
||
display:flex;flex-direction:column;
|
||
background:rgba(7,7,18,.98);
|
||
border-left:1px solid rgba(0,245,255,.1);
|
||
box-shadow:-20px 0 80px rgba(0,0,0,.7),-4px 0 24px rgba(0,245,255,.04);
|
||
transform:translateX(100%);
|
||
transition:transform .32s cubic-bezier(.22,1,.36,1);
|
||
overflow:hidden;
|
||
}
|
||
#chat-panel.open{transform:translateX(0)}
|
||
|
||
/* Header */
|
||
.cp-hdr{
|
||
display:flex;align-items:center;gap:8px;
|
||
padding:12px 14px;
|
||
background:rgba(5,5,14,.9);
|
||
border-bottom:1px solid rgba(255,255,255,.07);
|
||
flex-shrink:0;
|
||
}
|
||
.cp-hdr-title{font-size:.98rem;font-weight:800;color:#fff;flex:1}
|
||
.cp-hdr-close,.cp-hdr-back,.cp-hdr-call{
|
||
width:32px;height:32px;border-radius:8px;
|
||
background:rgba(255,255,255,.07);border:none;
|
||
color:rgba(255,255,255,.5);font-size:.9rem;
|
||
cursor:pointer;display:flex;align-items:center;justify-content:center;
|
||
transition:all .15s;flex-shrink:0;
|
||
}
|
||
.cp-hdr-close:hover,.cp-hdr-back:hover{background:rgba(255,255,255,.14);color:#fff}
|
||
.cp-hdr-call{color:#22c55e}
|
||
.cp-hdr-call:hover{background:rgba(34,197,94,.2);color:#22c55e}
|
||
.cp-hdr-ava{
|
||
width:32px;height:32px;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:.75rem;font-weight:800;color:#fff;
|
||
}
|
||
.cp-hdr-ava img{width:100%;height:100%;object-fit:cover}
|
||
.cp-hdr-name{font-size:.88rem;font-weight:700;color:#fff;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||
|
||
/* Conversation list */
|
||
#cp-list{display:flex;flex-direction:column;flex:1;min-height:0}
|
||
#cp-convs{flex:1;overflow-y:auto;padding:8px}
|
||
#cp-convs::-webkit-scrollbar{width:3px}
|
||
#cp-convs::-webkit-scrollbar-thumb{background:rgba(255,255,255,.1);border-radius:2px}
|
||
|
||
.cp-conv-item{
|
||
display:flex;align-items:center;gap:12px;
|
||
padding:11px 12px;border-radius:12px;cursor:pointer;
|
||
transition:background .15s;position:relative;
|
||
border:1px solid transparent;
|
||
}
|
||
.cp-conv-item:hover{background:rgba(255,255,255,.05);border-color:rgba(255,255,255,.07)}
|
||
.cp-conv-item.unread{background:rgba(0,245,255,.04);border-color:rgba(0,245,255,.1)}
|
||
.cp-conv-ava{
|
||
width:44px;height:44px;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:1rem;font-weight:800;color:#fff;
|
||
}
|
||
.cp-conv-ava img{width:100%;height:100%;object-fit:cover}
|
||
.cp-conv-body{flex:1;min-width:0}
|
||
.cp-conv-name{font-size:.88rem;font-weight:700;color:#fff;margin-bottom:3px}
|
||
.cp-conv-preview{font-size:.76rem;color:rgba(255,255,255,.35);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||
.cp-conv-item.unread .cp-conv-preview{color:rgba(255,255,255,.65)}
|
||
.cp-conv-meta{display:flex;flex-direction:column;align-items:flex-end;gap:5px;flex-shrink:0}
|
||
.cp-conv-time{font-size:.65rem;color:rgba(255,255,255,.2)}
|
||
.cp-unread-badge{
|
||
min-width:18px;height:18px;border-radius:9px;
|
||
background:var(--accent2);color:#05050e;
|
||
font-size:.58rem;font-weight:900;
|
||
display:flex;align-items:center;justify-content:center;
|
||
padding:0 4px;
|
||
}
|
||
|
||
.cp-new-btn{
|
||
margin:12px;padding:11px;border-radius:12px;border:1px dashed rgba(0,245,255,.2);
|
||
background:rgba(0,245,255,.04);color:var(--accent2);
|
||
font-size:.82rem;font-weight:700;cursor:pointer;text-align:center;
|
||
transition:all .15s;text-decoration:none;display:block;
|
||
}
|
||
.cp-new-btn:hover{background:rgba(0,245,255,.1);border-color:rgba(0,245,255,.4)}
|
||
.cp-empty{padding:40px 20px;text-align:center;color:rgba(255,255,255,.2);font-size:.84rem}
|
||
.cp-empty i{font-size:2rem;display:block;margin-bottom:10px;opacity:.2}
|
||
|
||
/* Thread view */
|
||
#cp-thread{display:none;flex-direction:column;flex:1;min-height:0}
|
||
#cp-thread.active{display:flex}
|
||
|
||
#cp-msgs{
|
||
flex:1;overflow-y:auto;
|
||
padding:14px 14px 8px;
|
||
display:flex;flex-direction:column;gap:4px;
|
||
-webkit-overflow-scrolling:touch;
|
||
}
|
||
#cp-msgs::-webkit-scrollbar{width:3px}
|
||
#cp-msgs::-webkit-scrollbar-thumb{background:rgba(255,255,255,.08);border-radius:2px}
|
||
|
||
.cpm{display:flex;gap:8px;max-width:86%;align-items:flex-end}
|
||
.cpm.mine{align-self:flex-end;flex-direction:row-reverse}
|
||
.cpm.theirs{align-self:flex-start}
|
||
.cpm-ava{
|
||
width:26px;height:26px;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:.6rem;font-weight:800;color:#fff;
|
||
}
|
||
.cpm-ava img{width:100%;height:100%;object-fit:cover}
|
||
.cpm.mine .cpm-ava{display:none}
|
||
.cpm-bubble{
|
||
padding:9px 13px;border-radius:18px;
|
||
font-size:.86rem;line-height:1.5;word-break:break-word;
|
||
}
|
||
.cpm.mine .cpm-bubble{
|
||
background:linear-gradient(135deg,var(--accent2),#00d4de);
|
||
color:#05050e;font-weight:600;
|
||
border-bottom-right-radius:4px;
|
||
}
|
||
.cpm.theirs .cpm-bubble{
|
||
background:rgba(255,255,255,.09);
|
||
border:1px solid rgba(255,255,255,.08);
|
||
color:rgba(255,255,255,.9);
|
||
border-bottom-left-radius:4px;
|
||
}
|
||
.cpm-time{font-size:.58rem;color:rgba(255,255,255,.22);align-self:flex-end;margin-bottom:2px;flex-shrink:0}
|
||
.cp-date-sep{
|
||
text-align:center;font-size:.62rem;color:rgba(255,255,255,.2);
|
||
padding:10px 0 4px;font-weight:600;letter-spacing:.06em;
|
||
}
|
||
|
||
/* Media messages */
|
||
.cpm-img{
|
||
max-width:200px;max-height:200px;border-radius:12px;
|
||
cursor:pointer;display:block;object-fit:cover;
|
||
transition:opacity .15s;
|
||
}
|
||
.cpm-img:hover{opacity:.88}
|
||
.cpm-gif{
|
||
max-width:200px;border-radius:12px;display:block;
|
||
}
|
||
|
||
/* Share card in panel */
|
||
.cp-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:12px;padding:9px 11px;text-decoration:none;max-width:240px;
|
||
transition:all .15s;
|
||
}
|
||
.cp-share-card:hover{background:rgba(0,245,255,.12);border-color:rgba(0,245,255,.35)}
|
||
.cp-share-img{width:50px;height:70px;border-radius:7px;overflow:hidden;flex-shrink:0;background:rgba(255,255,255,.05)}
|
||
.cp-share-img img{width:100%;height:100%;object-fit:cover;display:block}
|
||
.cp-share-title{font-size:.78rem;font-weight:800;color:#fff;line-height:1.3;margin-bottom:2px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
|
||
.cp-share-ep{font-size:.68rem;color:rgba(255,255,255,.45)}
|
||
.cp-share-play{font-size:.66rem;color:var(--accent2);display:flex;align-items:center;gap:3px;margin-top:4px;font-weight:700}
|
||
|
||
/* Input area */
|
||
#cp-input-wrap{
|
||
padding:8px 10px;
|
||
background:rgba(5,5,14,.95);
|
||
border-top:1px solid rgba(255,255,255,.07);
|
||
flex-shrink:0;
|
||
padding-bottom:max(8px,env(safe-area-inset-bottom));
|
||
}
|
||
.cp-toolbar{
|
||
display:flex;align-items:center;gap:6px;
|
||
padding:6px 0 8px;
|
||
border-bottom:1px solid rgba(255,255,255,.06);
|
||
margin-bottom:6px;
|
||
}
|
||
.cp-tool-btn{
|
||
width:38px;height:38px;border-radius:10px;border:none;
|
||
background:rgba(255,255,255,.06);color:rgba(255,255,255,.4);
|
||
font-size:.88rem;cursor:pointer;
|
||
display:flex;align-items:center;justify-content:center;
|
||
transition:all .15s;flex-shrink:0;
|
||
}
|
||
.cp-tool-btn:hover{background:rgba(255,255,255,.13);color:#fff}
|
||
.cp-tool-btn.active{background:rgba(0,245,255,.12);color:var(--accent2)}
|
||
.cp-form{display:flex;align-items:flex-end;gap:8px}
|
||
#cp-textarea{
|
||
flex:1;background:rgba(255,255,255,.08);
|
||
border:1px solid rgba(255,255,255,.1);border-radius:20px;
|
||
padding:10px 14px;color:#fff;font-size:.88rem;font-family:inherit;
|
||
resize:none;max-height:100px;overflow-y:auto;min-height:40px;
|
||
line-height:1.4;outline:none;-webkit-appearance:none;
|
||
transition:border-color .15s;
|
||
}
|
||
#cp-textarea:focus{border-color:rgba(0,245,255,.35)}
|
||
#cp-textarea::placeholder{color:rgba(255,255,255,.22)}
|
||
#cp-send-btn{
|
||
width:40px;height:40px;border-radius:50%;flex-shrink:0;
|
||
background:linear-gradient(135deg,var(--accent2),#00c6d4);
|
||
border:none;color:#05050e;font-size:.95rem;cursor:pointer;
|
||
display:flex;align-items:center;justify-content:center;
|
||
transition:all .15s;
|
||
}
|
||
#cp-send-btn:hover{transform:scale(1.08);box-shadow:0 0 16px rgba(0,245,255,.5)}
|
||
#cp-send-btn:disabled{opacity:.35;transform:none;cursor:default}
|
||
|
||
/* Emoji picker */
|
||
#cp-emoji-picker{
|
||
display:none;
|
||
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;
|
||
}
|
||
#cp-emoji-picker.show{display:flex;flex-wrap:wrap;gap:2px}
|
||
.cp-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;
|
||
}
|
||
.cp-emoji-btn:hover{background:rgba(255,255,255,.1)}
|
||
|
||
/* GIF picker */
|
||
#cp-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;
|
||
}
|
||
#cp-gif-picker.show{display:block}
|
||
.cp-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;
|
||
}
|
||
.cp-gif-search::placeholder{color:rgba(255,255,255,.3)}
|
||
.cp-gif-grid{
|
||
display:grid;grid-template-columns:repeat(3,1fr);gap:4px;
|
||
max-height:160px;overflow-y:auto;
|
||
}
|
||
.cp-gif-item{
|
||
aspect-ratio:1;background:rgba(255,255,255,.05);border-radius:8px;
|
||
overflow:hidden;cursor:pointer;transition:opacity .15s;
|
||
}
|
||
.cp-gif-item:hover{opacity:.8}
|
||
.cp-gif-item img{width:100%;height:100%;object-fit:cover;display:block}
|
||
.cp-gif-placeholder{
|
||
padding:20px;text-align:center;color:rgba(255,255,255,.25);font-size:.78rem;
|
||
}
|
||
|
||
/* Loading skeleton */
|
||
.cp-loading{padding:20px;text-align:center;color:rgba(255,255,255,.2);font-size:.82rem}
|
||
|
||
/* Mobile nav chat button */
|
||
.mbn-a.mbn-chat.on{color:var(--accent2)}
|
||
.mbn-a.mbn-chat.on i{filter:drop-shadow(0 0 6px rgba(0,245,255,.85))}
|
||
.mbn-a.mbn-chat.on::after{background:linear-gradient(90deg,var(--accent2),var(--accent))}
|
||
.mbn-chat-badge{
|
||
position:absolute;top:4px;right:calc(50% - 14px);
|
||
min-width:14px;height:14px;border-radius:7px;
|
||
background:var(--accent);color:#fff;
|
||
font-size:.5rem;font-weight:900;
|
||
display:flex;align-items:center;justify-content:center;
|
||
padding:0 3px;
|
||
}
|
||
|
||
@media(max-width:900px){
|
||
#chat-panel{
|
||
width:100vw;border-left:none;border-top:1px solid rgba(0,245,255,.1);
|
||
top:0;
|
||
}
|
||
}
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
INCOMING CALL OVERLAY
|
||
════════════════════════════════════════════════════ */
|
||
#call-overlay{
|
||
display:none;
|
||
position:fixed;inset:0;z-index:99998;
|
||
background:rgba(0,0,0,.88);backdrop-filter:blur(20px);
|
||
align-items:center;justify-content:center;flex-direction:column;
|
||
gap:24px;
|
||
}
|
||
#call-overlay.show{display:flex}
|
||
.call-ava{
|
||
width:90px;height:90px;border-radius:50%;
|
||
background:linear-gradient(135deg,var(--accent2),var(--accent));
|
||
display:flex;align-items:center;justify-content:center;
|
||
font-size:2rem;font-weight:800;color:#fff;overflow:hidden;
|
||
box-shadow:0 0 0 8px rgba(0,245,255,.15),0 0 0 16px rgba(0,245,255,.07);
|
||
animation:call-ring 1.4s ease-in-out infinite;
|
||
}
|
||
.call-ava img{width:100%;height:100%;object-fit:cover}
|
||
@keyframes call-ring{
|
||
0%,100%{box-shadow:0 0 0 8px rgba(0,245,255,.15),0 0 0 16px rgba(0,245,255,.07)}
|
||
50%{box-shadow:0 0 0 14px rgba(0,245,255,.2),0 0 0 28px rgba(0,245,255,.06)}
|
||
}
|
||
.call-name{font-size:1.4rem;font-weight:800;color:#fff;text-align:center}
|
||
.call-status{font-size:.88rem;color:rgba(255,255,255,.5);text-align:center}
|
||
.call-btns{display:flex;gap:28px;margin-top:8px}
|
||
.call-btn{
|
||
width:64px;height:64px;border-radius:50%;border:none;cursor:pointer;
|
||
display:flex;align-items:center;justify-content:center;
|
||
font-size:1.5rem;color:#fff;transition:transform .15s,box-shadow .15s;
|
||
}
|
||
.call-btn:active{transform:scale(.92)}
|
||
.call-btn-accept{
|
||
background:linear-gradient(135deg,#22c55e,#16a34a);
|
||
box-shadow:0 0 32px rgba(34,197,94,.55);
|
||
}
|
||
.call-btn-accept:hover{box-shadow:0 0 44px rgba(34,197,94,.7)}
|
||
.call-btn-decline{
|
||
background:linear-gradient(135deg,#ef4444,#dc2626);
|
||
box-shadow:0 0 32px rgba(239,68,68,.55);
|
||
}
|
||
.call-btn-decline:hover{box-shadow:0 0 44px rgba(239,68,68,.7)}
|
||
.call-btn-end{
|
||
background:linear-gradient(135deg,#ef4444,#dc2626);
|
||
box-shadow:0 0 32px rgba(239,68,68,.55);
|
||
}
|
||
|
||
/* Active call bar (small, top of screen) */
|
||
#call-bar{
|
||
display:none;
|
||
position:fixed;top:64px;left:50%;transform:translateX(-50%);z-index:99997;
|
||
background:rgba(34,197,94,.15);border:1px solid rgba(34,197,94,.4);
|
||
border-radius:999px;padding:8px 18px;
|
||
align-items:center;gap:10px;
|
||
backdrop-filter:blur(12px);
|
||
box-shadow:0 4px 20px rgba(0,0,0,.4);
|
||
}
|
||
#call-bar.show{display:flex}
|
||
.call-bar-dot{
|
||
width:8px;height:8px;border-radius:50%;background:#22c55e;
|
||
animation:call-dot-pulse 1s ease-in-out infinite;
|
||
}
|
||
@keyframes call-dot-pulse{0%,100%{opacity:1}50%{opacity:.3}}
|
||
.call-bar-name{font-size:.82rem;font-weight:700;color:#fff}
|
||
.call-bar-timer{font-size:.78rem;color:rgba(255,255,255,.6);min-width:40px}
|
||
.call-bar-end{
|
||
padding:4px 12px;border-radius:999px;border:none;cursor:pointer;
|
||
background:rgba(239,68,68,.8);color:#fff;font-size:.75rem;font-weight:700;
|
||
transition:background .15s;
|
||
}
|
||
.call-bar-end:hover{background:#ef4444}
|
||
|
||
</style>
|
||
<link rel="stylesheet" href="/css/premium-cosmetics.css">
|
||
@stack('styles')
|
||
</head>
|
||
<body @auth @if(auth()->user()->entry_effect && auth()->user()->hasPerk('entry_effect'))class="entry-{{ auth()->user()->entry_effect }}"@endif @endauth>
|
||
|
||
{{-- Ambient floating orbs (CSS animated, no perf cost) --}}
|
||
<div class="amb amb-1" aria-hidden="true"></div>
|
||
<div class="amb amb-2" aria-hidden="true"></div>
|
||
<div class="amb amb-3" aria-hidden="true"></div>
|
||
|
||
{{-- Scroll progress bar --}}
|
||
<div id="scroll-progress" aria-hidden="true"></div>
|
||
|
||
{{-- Scroll to top button --}}
|
||
<button id="scroll-top" aria-label="Başa dön" title="Başa dön">
|
||
<i class="bi bi-chevron-up"></i>
|
||
</button>
|
||
|
||
<div id="splash">
|
||
<div class="splash-logo">ANIMEXE</div>
|
||
<div class="splash-bar-wrap"><div class="splash-bar"></div></div>
|
||
<div class="splash-dots"><span></span><span></span><span></span></div>
|
||
</div>
|
||
|
||
<nav id="topnav">
|
||
<a href="{{ route('home') }}" class="nav-logo">ANIMEXE</a>
|
||
|
||
<ul class="nav-links">
|
||
<li><a href="{{ route('home') }}" class="{{ request()->routeIs('home') ? 'on' : '' }}">Ana Sayfa</a></li>
|
||
<li><a href="{{ route('search') }}?type=series" class="{{ request()->is('search') && request('type')=='series' ? 'on' : '' }}">Diziler</a></li>
|
||
<li><a href="{{ route('search') }}?type=movie" class="{{ request()->is('search') && request('type')=='movie' ? 'on' : '' }}">Filmler</a></li>
|
||
<li><a href="{{ route('blog.index') }}" class="{{ request()->routeIs('blog.*') ? 'on' : '' }}"><i class="bi bi-journal-richtext" style="margin-right:4px"></i>Blog</a></li>
|
||
<li><a href="{{ route('anime.request') }}" class="{{ request()->routeIs('anime.request*') ? 'on' : '' }}"><i class="bi bi-plus-circle" style="margin-right:4px"></i>İstek</a></li>
|
||
<li><a href="{{ route('tribunal.index') }}" class="{{ request()->routeIs('tribunal.*') ? 'on' : '' }}" style="color:#ff9f0a;border-color:rgba(255,159,10,.2)"><i class="bi bi-balance" style="margin-right:4px"></i>Mahkeme</a></li>
|
||
<li><a href="{{ route('premium.plans') }}" class="{{ request()->routeIs('premium.*') ? 'on' : '' }}" style="color:#ffd700;border-color:rgba(255,215,0,.2)"><i class="bi bi-stars" style="margin-right:4px"></i>Premium</a></li>
|
||
@php $navShowMessages = \App\Models\Setting::get('nav_show_messages', '1'); @endphp
|
||
@if($navShowMessages)
|
||
<li><a href="{{ route('messages.index') }}" class="{{ request()->routeIs('messages.*') ? 'on' : '' }}" style="color:var(--accent2);border-color:rgba(0,245,255,.2)"><i class="bi bi-chat-dots" style="margin-right:4px"></i>Mesajlar @auth @if($unreadMsgCount??0)<span style="background:var(--accent2);color:#05050e;border-radius:8px;padding:0 5px;font-size:.6rem;font-weight:800;margin-left:2px">{{ $unreadMsgCount }}</span>@endif @endauth</a></li>
|
||
@else
|
||
<li><a href="{{ route('ai.index') }}" class="{{ request()->routeIs('ai.*') ? 'on' : '' }}" style="color:var(--accent3);border-color:rgba(184,77,255,.3)"><i class="bi bi-stars" style="margin-right:4px"></i>AI @guest<i class="bi bi-lock-fill" style="font-size:.6rem;opacity:.7"></i>@endguest</a></li>
|
||
@endif
|
||
</ul>
|
||
|
||
<div class="nav-search">
|
||
<form action="{{ route('search') }}" method="GET" class="ns-form" id="ns-form">
|
||
<i class="bi bi-search ns-icon"></i>
|
||
<input type="text" name="q" id="ns-input" placeholder="Anime ara..." value="{{ request('q') }}" autocomplete="off">
|
||
<div class="ns-ac" id="ns-ac" role="listbox"></div>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="nav-auth">
|
||
@auth
|
||
@php
|
||
$unreadNotifCount = \App\Models\UserNotification::where('user_id', auth()->id())->whereNull('read_at')->count();
|
||
$unreadMsgCount = 0;
|
||
try {
|
||
foreach(auth()->user()->conversations()->with('messages')->get() as $_conv) {
|
||
$unreadMsgCount += $_conv->unreadCountFor(auth()->id());
|
||
}
|
||
} catch(\Throwable $e) {}
|
||
@endphp
|
||
<button class="nav-bell" id="cp-nav-btn" onclick="chatPanelToggle()" title="Mesajlar" style="background:none;border:none;cursor:pointer;position:relative">
|
||
<i class="bi bi-chat-dots{{ $unreadMsgCount ? '-fill' : '' }}" id="cp-nav-icon"></i>
|
||
<span class="bell-badge" id="cp-nav-badge" style="{{ $unreadMsgCount ? '' : 'display:none' }}">{{ $unreadMsgCount > 9 ? '9+' : $unreadMsgCount }}</span>
|
||
</button>
|
||
<a href="{{ route('notifications') }}" class="nav-bell" title="Bildirimler">
|
||
<i class="bi bi-bell{{ $unreadNotifCount ? '-fill' : '' }}"></i>
|
||
@if($unreadNotifCount)<span class="bell-badge">{{ $unreadNotifCount > 9 ? '9+' : $unreadNotifCount }}</span>@endif
|
||
</a>
|
||
<div class="nav-user">
|
||
<div class="nav-avatar">{{ mb_substr(auth()->user()->name,0,1) }}</div>
|
||
<span class="nav-user-name d-none d-md-block">{{ auth()->user()->name }}</span>
|
||
<div class="nav-dropdown">
|
||
<a href="{{ route('profile') }}"><i class="bi bi-person"></i> Profilim</a>
|
||
<a href="{{ route('messages.index') }}"><i class="bi bi-chat-dots"></i> Mesajlar @if($unreadMsgCount)<span style="background:var(--accent2);color:#05050e;border-radius:10px;padding:1px 6px;font-size:.65rem;margin-left:4px">{{ $unreadMsgCount }}</span>@endif</a>
|
||
<a href="{{ route('notifications') }}"><i class="bi bi-bell"></i> Bildirimler @if($unreadNotifCount)<span style="background:var(--accent);color:#fff;border-radius:10px;padding:1px 6px;font-size:.65rem;margin-left:4px">{{ $unreadNotifCount }}</span>@endif</a>
|
||
<a href="{{ route('capsules.index') }}"><i class="bi bi-hourglass-split"></i> Kapsüllerim</a>
|
||
@if(auth()->user()->isPremium())
|
||
<a href="{{ route('profile.settings') }}" style="color:#ffd700"><i class="bi bi-stars"></i> Kozmetik Ayarları</a>
|
||
@else
|
||
<a href="{{ route('premium.plans') }}" style="color:#ffd700"><i class="bi bi-stars"></i> Premium'a Geç ✨</a>
|
||
@endif
|
||
@if(auth()->user()->role === 'admin')
|
||
<a href="{{ route('admin.dashboard') }}"><i class="bi bi-speedometer2"></i> Admin Panel</a>
|
||
@endif
|
||
<div class="sep"></div>
|
||
<form action="{{ route('frontend.logout') }}" method="POST" style="display:block">
|
||
@csrf
|
||
<button type="submit"><i class="bi bi-box-arrow-right"></i> Çıkış Yap</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
@else
|
||
<a href="{{ route('frontend.login') }}" class="btn-ghost">Giriş Yap</a>
|
||
<a href="{{ route('frontend.register') }}" class="btn-solid">Üye Ol</a>
|
||
@endauth
|
||
</div>
|
||
|
||
<button class="nav-ham" id="ham-btn"><i class="bi bi-list"></i></button>
|
||
</nav>
|
||
|
||
<div id="mob-menu">
|
||
@auth
|
||
<div class="mob-user-block">
|
||
<div class="mob-user-ava">{{ mb_substr(auth()->user()->name,0,1) }}</div>
|
||
<div class="mob-user-info">
|
||
<div class="mob-user-name">{{ auth()->user()->name }}</div>
|
||
<div class="mob-user-tier">{{ auth()->user()->isPremium() ? '⭐ Premium Üye' : 'Standart Üye' }}</div>
|
||
</div>
|
||
</div>
|
||
@endauth
|
||
|
||
<div class="mob-search">
|
||
<i class="bi bi-search ns-icon"></i>
|
||
<form action="{{ route('search') }}" method="GET">
|
||
<input type="text" name="q" placeholder="Anime ara..." value="{{ request('q') }}">
|
||
</form>
|
||
</div>
|
||
|
||
<div class="mob-nav-links">
|
||
<a href="{{ route('home') }}"><i class="bi bi-house"></i> Ana Sayfa</a>
|
||
<a href="{{ route('search') }}?type=series"><i class="bi bi-tv"></i> Anime Diziler</a>
|
||
<a href="{{ route('search') }}?type=movie"><i class="bi bi-film"></i> Anime Filmler</a>
|
||
<a href="{{ route('search') }}"><i class="bi bi-grid"></i> Tüm Animeler</a>
|
||
<a href="{{ route('blog.index') }}"><i class="bi bi-journal-richtext"></i> Blog</a>
|
||
<a href="{{ route('anime.request') }}"><i class="bi bi-plus-circle"></i> Anime İsteği</a>
|
||
<a href="{{ route('premium.plans') }}" style="color:#ffd700"><i class="bi bi-stars"></i> Premium</a>
|
||
@if($navShowMessages ?? \App\Models\Setting::getValue('nav_show_messages','1'))
|
||
<a href="{{ route('messages.index') }}" style="color:var(--accent2)"><i class="bi bi-chat-dots"></i> Mesajlar @auth @if($unreadMsgCount??0)<span style="background:var(--accent2);color:#05050e;border-radius:8px;padding:0 5px;font-size:.6rem;font-weight:800;margin-left:2px">{{ $unreadMsgCount }}</span>@endif @endauth</a>
|
||
@else
|
||
<a href="{{ route('ai.index') }}" style="color:var(--accent3)"><i class="bi bi-stars"></i> AI Asistan @guest<i class="bi bi-lock-fill" style="font-size:.65rem;opacity:.7"></i>@endguest</a>
|
||
@endif
|
||
</div>
|
||
|
||
@auth
|
||
<div class="mob-divider"></div>
|
||
<div class="mob-nav-links">
|
||
<a href="{{ route('profile') }}"><i class="bi bi-person-circle"></i> Profilim</a>
|
||
<a href="{{ route('messages.index') }}"><i class="bi bi-chat-dots"></i> Mesajlar @if($unreadMsgCount ?? 0)<span style="background:var(--accent2);color:#05050e;border-radius:10px;padding:1px 7px;font-size:.65rem;margin-left:4px">{{ $unreadMsgCount }}</span>@endif</a>
|
||
<a href="{{ route('notifications') }}"><i class="bi bi-bell"></i> Bildirimler @if($unreadNotifCount ?? 0)<span style="background:var(--accent);color:#fff;border-radius:10px;padding:1px 7px;font-size:.65rem;margin-left:4px">{{ $unreadNotifCount }}</span>@endif</a>
|
||
@if(auth()->user()->role==='admin')
|
||
<a href="{{ route('admin.dashboard') }}" style="color:var(--accent2)"><i class="bi bi-speedometer2"></i> Admin Panel</a>
|
||
@endif
|
||
<form action="{{ route('frontend.logout') }}" method="POST" style="display:block">
|
||
@csrf
|
||
<button type="submit" style="width:100%;text-align:left;padding:12px 16px;border-radius:var(--r);background:none;border:none;color:rgba(255,90,90,.85);font-weight:600;font-family:inherit;cursor:pointer;font-size:inherit;display:flex;align-items:center;gap:10px"><i class="bi bi-box-arrow-right" style="width:18px;text-align:center;opacity:.7"></i> Çıkış Yap</button>
|
||
</form>
|
||
</div>
|
||
@else
|
||
<div class="mob-auth">
|
||
<a href="{{ route('frontend.login') }}" class="login"><i class="bi bi-box-arrow-in-right"></i> Giriş Yap</a>
|
||
<a href="{{ route('frontend.register') }}" class="reg"><i class="bi bi-person-plus"></i> Üye Ol</a>
|
||
</div>
|
||
@endauth
|
||
</div>
|
||
|
||
{{-- ═══════════════════════════════════════════════════════
|
||
MOBİL ALT NAVİGASYON ÇUBUĞU (90% mobil ziyaretçi)
|
||
════════════════════════════════════════════════════════ --}}
|
||
<nav id="mob-bottom-nav" aria-label="Alt Navigasyon">
|
||
<ul class="mbn-list">
|
||
<li>
|
||
<a href="{{ route('home') }}"
|
||
class="mbn-a {{ request()->routeIs('home') ? 'on' : '' }}"
|
||
aria-label="Ana Sayfa">
|
||
<i class="bi bi-house{{ request()->routeIs('home') ? '-fill' : '' }}"></i>
|
||
<span>Anasayfa</span>
|
||
</a>
|
||
</li>
|
||
<li>
|
||
<a href="{{ route('search') }}"
|
||
class="mbn-a {{ request()->routeIs('search') && !request('type') ? 'on' : '' }}"
|
||
aria-label="Keşfet">
|
||
<i class="bi bi-compass{{ request()->routeIs('search') && !request('type') ? '-fill' : '' }}"></i>
|
||
<span>Keşfet</span>
|
||
</a>
|
||
</li>
|
||
<li>
|
||
<a href="{{ route('search') }}?type=series"
|
||
class="mbn-a {{ request()->routeIs('search') && request('type')==='series' ? 'on' : '' }}"
|
||
aria-label="Diziler">
|
||
<i class="bi bi-play-circle{{ request()->routeIs('search') && request('type')==='series' ? '-fill' : '' }}"></i>
|
||
<span>Diziler</span>
|
||
</a>
|
||
</li>
|
||
<li>
|
||
@auth
|
||
<button onclick="chatPanelToggle()"
|
||
class="mbn-a mbn-chat {{ request()->routeIs('messages.*') ? 'on' : '' }}"
|
||
aria-label="Mesajlar" style="background:none;border:none;width:100%;position:relative">
|
||
<i class="bi bi-chat-dots{{ ($unreadMsgCount??0) ? '-fill' : '' }}"></i>
|
||
@if($unreadMsgCount??0)<span class="mbn-chat-badge">{{ ($unreadMsgCount??0) > 9 ? '9+' : ($unreadMsgCount??0) }}</span>@endif
|
||
<span>Chat</span>
|
||
</button>
|
||
@else
|
||
<a href="{{ route('ai.index') }}"
|
||
class="mbn-a mbn-ai {{ request()->routeIs('ai.*') ? 'on' : '' }}"
|
||
aria-label="AI Asistan">
|
||
<i class="bi bi-stars"></i>
|
||
<span>AI</span>
|
||
</a>
|
||
@endauth
|
||
</li>
|
||
<li>
|
||
@auth
|
||
<a href="{{ route('profile') }}"
|
||
class="mbn-a {{ request()->routeIs('profile*') ? 'on' : '' }}"
|
||
aria-label="Profilim">
|
||
<i class="bi bi-person{{ request()->routeIs('profile*') ? '-fill' : '' }}"></i>
|
||
<span>Profil</span>
|
||
</a>
|
||
@else
|
||
<a href="{{ route('frontend.register') }}"
|
||
class="mbn-a {{ request()->routeIs('frontend.register') ? 'on' : '' }}"
|
||
aria-label="Üye Ol">
|
||
<i class="bi bi-person-plus{{ request()->routeIs('frontend.register') ? '-fill' : '' }}"></i>
|
||
<span>Üye Ol</span>
|
||
</a>
|
||
@endauth
|
||
</li>
|
||
</ul>
|
||
</nav>
|
||
|
||
{{-- ════════════════════════════════════════════════════
|
||
CHAT PANEL (site genelinde erişilebilir)
|
||
════════════════════════════════════════════════════ --}}
|
||
<div id="cp-backdrop" onclick="chatPanelClose()"></div>
|
||
<div id="chat-panel">
|
||
|
||
{{-- Konuşma listesi --}}
|
||
<div id="cp-list">
|
||
<div class="cp-hdr">
|
||
<span class="cp-hdr-title"><i class="bi bi-chat-dots-fill" style="color:var(--accent2);margin-right:8px"></i>Mesajlar</span>
|
||
<a href="{{ route('messages.index') }}" class="cp-hdr-close" title="Tam sayfa aç" style="text-decoration:none;font-size:.8rem">
|
||
<i class="bi bi-box-arrow-up-right"></i>
|
||
</a>
|
||
<button class="cp-hdr-close" onclick="chatPanelClose()" title="Kapat">
|
||
<i class="bi bi-x-lg"></i>
|
||
</button>
|
||
</div>
|
||
<div id="cp-convs">
|
||
<div class="cp-loading"><i class="bi bi-hourglass" style="font-size:1.2rem;display:block;margin-bottom:6px;opacity:.3"></i>Yükleniyor…</div>
|
||
</div>
|
||
<a href="{{ route('messages.index') }}" class="cp-new-btn">
|
||
<i class="bi bi-plus-circle"></i> Tüm Mesajlar / Yeni Sohbet
|
||
</a>
|
||
</div>
|
||
|
||
{{-- Sohbet ekranı --}}
|
||
<div id="cp-thread">
|
||
<div class="cp-hdr">
|
||
<button class="cp-hdr-back" onclick="cpShowList()"><i class="bi bi-arrow-left"></i></button>
|
||
<div class="cp-hdr-ava" id="cp-t-ava"></div>
|
||
<div style="flex:1;min-width:0">
|
||
<div class="cp-hdr-name" id="cp-t-name"></div>
|
||
</div>
|
||
@auth
|
||
<button class="cp-hdr-call" id="cp-t-call-btn" onclick="cpStartCall()" title="Sesli ara">
|
||
<i class="bi bi-telephone-fill"></i>
|
||
</button>
|
||
@endauth
|
||
<a id="cp-t-fulllink" href="#" class="cp-hdr-close" style="text-decoration:none;font-size:.8rem" title="Tam sayfada aç">
|
||
<i class="bi bi-box-arrow-up-right"></i>
|
||
</a>
|
||
<button class="cp-hdr-close" onclick="chatPanelClose()"><i class="bi bi-x-lg"></i></button>
|
||
</div>
|
||
<div id="cp-msgs"></div>
|
||
<div id="cp-input-wrap">
|
||
{{-- Emoji picker (desktop only) --}}
|
||
<div id="cp-emoji-picker"></div>
|
||
{{-- GIF picker --}}
|
||
<div id="cp-gif-picker">
|
||
<input type="text" class="cp-gif-search" id="cp-gif-input" placeholder="GIF ara…">
|
||
<div class="cp-gif-grid" id="cp-gif-grid">
|
||
<div class="cp-gif-placeholder">GIF aramak için yazmaya başla</div>
|
||
</div>
|
||
</div>
|
||
{{-- Toolbar: only desktop emoji + both gif/image --}}
|
||
<div class="cp-toolbar">
|
||
<button class="cp-tool-btn" id="cp-emoji-btn" onclick="cpToggleEmoji()" title="Emoji" style="display:none">
|
||
<i class="bi bi-emoji-smile"></i>
|
||
</button>
|
||
<button class="cp-tool-btn" id="cp-gif-btn" onclick="cpToggleGif()" title="GIF">
|
||
<span style="font-size:.65rem;font-weight:800;letter-spacing:.03em">GIF</span>
|
||
</button>
|
||
<label class="cp-tool-btn" title="Resim gönder" style="cursor:pointer">
|
||
<i class="bi bi-image"></i>
|
||
<input type="file" id="cp-img-input" accept="image/*" style="display:none" onchange="cpSendImage(this)">
|
||
</label>
|
||
<div style="flex:1"></div>
|
||
</div>
|
||
<div class="cp-form">
|
||
<textarea id="cp-textarea" placeholder="Mesaj yaz…" rows="1" maxlength="2000"></textarea>
|
||
<button id="cp-send-btn" onclick="cpSend()"><i class="bi bi-send-fill"></i></button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
{{-- ═══ INCOMING CALL OVERLAY ════════════════════════════════════════════════ --}}
|
||
<div id="call-overlay">
|
||
<div class="call-ava" id="call-ava-el"></div>
|
||
<div class="call-name" id="call-name-el"></div>
|
||
<div class="call-status" id="call-status-el">Sesli arama…</div>
|
||
<div class="call-btns" id="call-btns-el">
|
||
<button class="call-btn call-btn-decline" onclick="vcDecline()" title="Reddet">
|
||
<i class="bi bi-telephone-x-fill"></i>
|
||
</button>
|
||
<button class="call-btn call-btn-accept" onclick="vcAnswer()" title="Kabul et">
|
||
<i class="bi bi-telephone-fill"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Active call bar --}}
|
||
<div id="call-bar">
|
||
<div class="call-bar-dot"></div>
|
||
<span class="call-bar-name" id="call-bar-name"></span>
|
||
<span class="call-bar-timer" id="call-bar-timer">00:00</span>
|
||
<button class="call-bar-end" onclick="vcEnd()">Kapat</button>
|
||
</div>
|
||
|
||
|
||
<div id="page-content">@yield('content')</div>
|
||
|
||
<footer>
|
||
<div class="footer-in">
|
||
<div class="footer-brand">
|
||
<div class="logo">ANIMEXE</div>
|
||
<p>Türkçe altyazılı ve dublajlı anime topluluğu platformu. Tüm içerikler üçüncü taraf kaynaklara aittir.</p>
|
||
</div>
|
||
<div class="footer-col">
|
||
<h5>Keşfet</h5>
|
||
<ul>
|
||
<li><a href="{{ route('search') }}?type=series">Anime Diziler</a></li>
|
||
<li><a href="{{ route('search') }}?type=movie">Anime Filmler</a></li>
|
||
<li><a href="{{ route('search') }}?status=ongoing">Devam Edenler</a></li>
|
||
<li><a href="{{ route('search') }}?status=completed">Tamamlananlar</a></li>
|
||
<li><a href="{{ route('blog.index') }}">Anime Blog</a></li>
|
||
<li><a href="{{ route('tribunal.index') }}">Anime Mahkemesi</a></li>
|
||
</ul>
|
||
</div>
|
||
<div class="footer-col">
|
||
<h5>Hesap</h5>
|
||
<ul>
|
||
@guest
|
||
<li><a href="{{ route('frontend.login') }}">Giriş Yap</a></li>
|
||
<li><a href="{{ route('frontend.register') }}">Üye Ol</a></li>
|
||
@else
|
||
<li><a href="{{ route('profile') }}">Profilim</a></li>
|
||
@endguest
|
||
</ul>
|
||
</div>
|
||
<div class="footer-col">
|
||
<h5>Yasal</h5>
|
||
<ul>
|
||
<li><a href="{{ route('legal.terms') }}">Kullanım Koşulları</a></li>
|
||
<li><a href="{{ route('legal.privacy') }}">Gizlilik Politikası</a></li>
|
||
<li><a href="{{ route('legal.dmca') }}">Telif Hakkı & DMCA</a></li>
|
||
<li><a href="mailto:iletisim@animexe.com">İletişim</a></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="footer-bottom">
|
||
<span>© {{ date('Y') }} Animexe — Tüm hakları saklıdır. Platform yalnızca teknik aracı konumundadır; içerikler ilgili hak sahiplerine aittir. · <a href="https://ayris.tech" target="_blank" rel="noopener" style="color:inherit;opacity:.75">Created by ayris.tech</a></span>
|
||
<span style="display:flex;gap:16px;flex-wrap:wrap;justify-content:flex-end">
|
||
<a href="{{ route('legal.terms') }}" style="color:inherit;opacity:.6;font-size:.78rem">Kullanım Koşulları</a>
|
||
<a href="{{ route('legal.privacy') }}" style="color:inherit;opacity:.6;font-size:.78rem">Gizlilik</a>
|
||
<a href="{{ route('legal.dmca') }}" style="color:inherit;opacity:.6;font-size:.78rem">DMCA</a>
|
||
</span>
|
||
</div>
|
||
<div style="margin-top:8px;font-size:.7rem;opacity:.35">
|
||
<a href="https://bumin.tr/" title="film izle" style="color:inherit;text-decoration:none">film izle</a>
|
||
</div>
|
||
{{-- Partnerler — resources/data/partners.json'dan okunur. Cache anahtarı dosya
|
||
değişim zamanına bağlı: JSON güncellenip deploy edilince otomatik tazelenir. --}}
|
||
@php
|
||
$__pFile = resource_path('data/partners.json');
|
||
$__partners = \Illuminate\Support\Facades\Cache::remember(
|
||
'footer_partners_' . (is_file($__pFile) ? @filemtime($__pFile) : '0'),
|
||
86400,
|
||
function () use ($__pFile) {
|
||
if (! is_file($__pFile)) return [];
|
||
$rows = json_decode((string) @file_get_contents($__pFile), true);
|
||
if (! is_array($rows)) return [];
|
||
return array_values(array_filter($rows, fn ($r) =>
|
||
is_array($r)
|
||
&& ! empty($r['url']) && ! empty($r['anchor'])
|
||
&& filter_var($r['url'], FILTER_VALIDATE_URL)
|
||
&& preg_match('#^https?://#i', $r['url'])
|
||
));
|
||
}
|
||
);
|
||
@endphp
|
||
@if(! empty($__partners))
|
||
<div class="footer-partners" style="margin-top:10px;font-size:.72rem;opacity:.45;line-height:2">
|
||
<span style="opacity:.7">Partnerler:</span>
|
||
@foreach($__partners as $__p)
|
||
<a href="{{ $__p['url'] }}"
|
||
@isset($__p['title']) title="{{ $__p['title'] }}" @endisset
|
||
rel="{{ $__p['rel'] ?? 'dofollow' }} noopener"
|
||
target="_blank"
|
||
style="color:inherit;text-decoration:none;margin-right:12px">{{ $__p['anchor'] }}</a>
|
||
@endforeach
|
||
</div>
|
||
@endif
|
||
</footer>
|
||
|
||
<script>
|
||
document.getElementById('ham-btn').addEventListener('click',()=>{
|
||
document.getElementById('mob-menu').classList.toggle('open');
|
||
});
|
||
</script>
|
||
@stack('scripts')
|
||
|
||
{{-- ── Search Autocomplete ──────────────────────────────────────────────────── --}}
|
||
<script>
|
||
(function() {
|
||
const input = document.getElementById('ns-input');
|
||
const ac = document.getElementById('ns-ac');
|
||
if (!input || !ac) return;
|
||
|
||
let timer, focusIdx = -1, lastQ = '';
|
||
|
||
function typeLabel(type) {
|
||
return type === 'series' ? 'Dizi' : type === 'movie' ? 'Film' : 'OVA';
|
||
}
|
||
|
||
function render(results, q) {
|
||
if (!results.length) { ac.classList.remove('show'); return; }
|
||
const hl = (txt) => txt ? txt.replace(new RegExp('(' + q.replace(/[.*+?^${}()|[\]\\]/g,'\\$&') + ')', 'gi'), '<mark style="background:transparent;color:var(--accent2)">$1</mark>') : '';
|
||
ac.innerHTML = results.map((r, i) =>
|
||
`<a href="/anime/${r.slug}" class="ns-ac-item" data-idx="${i}" role="option">
|
||
${r.cover
|
||
? `<img src="${r.cover}" alt="${r.title}" loading="lazy">`
|
||
: `<div class="ns-ac-ph"><i class="bi bi-film" style="color:var(--text3)"></i></div>`
|
||
}
|
||
<div class="ns-ac-info">
|
||
<div class="ns-ac-title">${hl(r.title)}</div>
|
||
<div class="ns-ac-meta">${r.title_en ? hl(r.title_en) + ' · ' : ''}${r.year ?? ''}${r.episodes ? ' · ' + r.episodes + ' Bölüm' : ''}</div>
|
||
</div>
|
||
${r.type ? `<span class="ns-ac-type">${typeLabel(r.type)}</span>` : ''}
|
||
</a>`
|
||
).join('') +
|
||
`<a href="/search?q=${encodeURIComponent(q)}" class="ns-ac-all">Tüm sonuçları gör için →</a>`;
|
||
focusIdx = -1;
|
||
ac.classList.add('show');
|
||
}
|
||
|
||
function moveFocus(dir) {
|
||
const items = ac.querySelectorAll('.ns-ac-item');
|
||
if (!items.length) return;
|
||
items.forEach(el => el.classList.remove('focused'));
|
||
focusIdx = (focusIdx + dir + items.length + 1) % (items.length + 1) - 1;
|
||
if (focusIdx >= 0) items[focusIdx].classList.add('focused');
|
||
}
|
||
|
||
input.addEventListener('input', () => {
|
||
const q = input.value.trim();
|
||
if (q === lastQ) return;
|
||
lastQ = q;
|
||
clearTimeout(timer);
|
||
if (q.length < 2) { ac.classList.remove('show'); return; }
|
||
timer = setTimeout(async () => {
|
||
try {
|
||
const res = await fetch(`/search/suggest?q=${encodeURIComponent(q)}`);
|
||
const data = await res.json();
|
||
if (input.value.trim() === q) render(data.results || [], q);
|
||
} catch (_) {}
|
||
}, 220);
|
||
});
|
||
|
||
input.addEventListener('keydown', (e) => {
|
||
if (e.key === 'ArrowDown') { e.preventDefault(); moveFocus(1); }
|
||
if (e.key === 'ArrowUp') { e.preventDefault(); moveFocus(-1); }
|
||
if (e.key === 'Escape') { ac.classList.remove('show'); focusIdx = -1; }
|
||
if (e.key === 'Enter' && focusIdx >= 0) {
|
||
e.preventDefault();
|
||
const item = ac.querySelectorAll('.ns-ac-item')[focusIdx];
|
||
if (item) window.location.href = item.href;
|
||
}
|
||
});
|
||
|
||
document.addEventListener('click', (e) => {
|
||
if (!(e.target instanceof Node)) return;
|
||
if (!input.contains(e.target) && !ac.contains(e.target)) ac.classList.remove('show');
|
||
});
|
||
|
||
input.addEventListener('focus', () => {
|
||
if (input.value.trim().length >= 2 && ac.children.length) ac.classList.add('show');
|
||
});
|
||
})();
|
||
</script>
|
||
|
||
@auth
|
||
{{-- ── Floating AI Chat Widget ─────────────────────────────────── --}}
|
||
<style>
|
||
#ai-fab{
|
||
position:fixed;bottom:24px;right:24px;z-index:900;
|
||
width:56px;height:56px;border-radius:50%;border:none;cursor:pointer;
|
||
background:linear-gradient(135deg,var(--accent3),var(--accent));
|
||
color:#fff;font-size:1.4rem;
|
||
display:flex;align-items:center;justify-content:center;
|
||
box-shadow:0 0 0 0 rgba(184,77,255,.5),0 4px 20px rgba(184,77,255,.4);
|
||
animation:ai-pulse 2.8s infinite;
|
||
transition:transform .18s,box-shadow .18s;
|
||
}
|
||
#ai-fab:hover{transform:scale(1.08);box-shadow:0 0 32px rgba(184,77,255,.55),0 6px 24px rgba(255,45,125,.3)}
|
||
@keyframes ai-pulse{
|
||
0%,100%{box-shadow:0 0 0 0 rgba(184,77,255,.4),0 4px 20px rgba(184,77,255,.4)}
|
||
50%{box-shadow:0 0 0 10px rgba(184,77,255,0),0 4px 20px rgba(184,77,255,.4)}
|
||
}
|
||
#ai-panel{
|
||
position:fixed;bottom:92px;right:24px;z-index:899;
|
||
width:min(400px, calc(100vw - 32px));
|
||
background:linear-gradient(160deg,rgba(10,10,22,.99),rgba(6,6,16,.99));
|
||
border:1px solid rgba(184,77,255,.35);border-radius:20px;
|
||
box-shadow:0 24px 64px rgba(0,0,0,.7),0 0 60px rgba(184,77,255,.1);
|
||
display:flex;flex-direction:column;overflow:hidden;
|
||
transform:translateY(20px) scale(.96);opacity:0;pointer-events:none;
|
||
transition:transform .22s cubic-bezier(.22,1,.36,1),opacity .22s cubic-bezier(.22,1,.36,1);
|
||
height:min(560px, calc(100dvh - 120px));
|
||
}
|
||
#ai-panel.open{transform:translateY(0) scale(1);opacity:1;pointer-events:all}
|
||
.aip-head{
|
||
padding:13px 16px;display:flex;align-items:center;gap:10px;
|
||
background:linear-gradient(135deg,rgba(184,77,255,.18),rgba(255,45,125,.1));
|
||
border-bottom:1px solid rgba(184,77,255,.2);flex-shrink:0;
|
||
}
|
||
.aip-head-icon{
|
||
width:34px;height:34px;border-radius:50%;
|
||
background:linear-gradient(135deg,var(--accent3),var(--accent));
|
||
display:flex;align-items:center;justify-content:center;font-size:.9rem;color:#fff;
|
||
box-shadow:0 0 14px rgba(184,77,255,.5);flex-shrink:0;
|
||
}
|
||
.aip-head-info{flex:1;min-width:0}
|
||
.aip-head-title{font-size:.88rem;font-weight:700;color:var(--text);letter-spacing:.03em}
|
||
.aip-head-sub{font-size:.7rem;color:var(--text3);margin-top:1px;display:flex;align-items:center;gap:5px}
|
||
.aip-online-dot{width:6px;height:6px;border-radius:50%;background:#22c55e;display:inline-block;box-shadow:0 0 6px #22c55e}
|
||
.aip-head-actions{display:flex;gap:4px;flex-shrink:0}
|
||
.aip-close,.aip-clear{background:none;border:none;color:var(--text3);font-size:1rem;cursor:pointer;padding:5px 6px;border-radius:7px;transition:all .14s}
|
||
.aip-close:hover,.aip-clear:hover{color:var(--text);background:rgba(255,255,255,.07)}
|
||
.aip-msgs{
|
||
flex:1;overflow-y:auto;padding:14px 12px;display:flex;flex-direction:column;gap:10px;
|
||
scrollbar-width:thin;scrollbar-color:rgba(184,77,255,.25) transparent;
|
||
min-height:0;
|
||
}
|
||
.aip-msgs::-webkit-scrollbar{width:3px}
|
||
.aip-msgs::-webkit-scrollbar-thumb{background:rgba(184,77,255,.3);border-radius:3px}
|
||
.aip-msg-wrap{display:flex;flex-direction:column;gap:6px;max-width:92%}
|
||
.aip-msg-wrap.ai{align-self:flex-start}
|
||
.aip-msg-wrap.user{align-self:flex-end;align-items:flex-end}
|
||
.aip-msg{font-size:.84rem;line-height:1.6;padding:10px 13px;border-radius:14px;word-break:break-word}
|
||
.aip-msg.ai{
|
||
background:linear-gradient(135deg,rgba(184,77,255,.14),rgba(0,245,255,.07));
|
||
border:1px solid rgba(184,77,255,.22);color:var(--text);border-bottom-left-radius:4px;
|
||
}
|
||
.aip-msg.user{
|
||
background:linear-gradient(135deg,rgba(255,45,125,.2),rgba(184,77,255,.14));
|
||
border:1px solid rgba(255,45,125,.28);color:var(--text);border-bottom-right-radius:4px;
|
||
}
|
||
/* Markdown inside ai bubble */
|
||
.aip-msg.ai b,.aip-msg.ai strong{color:#e2d3ff;font-weight:700}
|
||
.aip-msg.ai em,.aip-msg.ai i{color:var(--text2);font-style:italic}
|
||
.aip-msg.ai ul{margin:6px 0 2px 16px;padding:0;list-style:disc}
|
||
.aip-msg.ai ol{margin:6px 0 2px 20px;padding:0}
|
||
.aip-msg.ai li{margin-bottom:3px}
|
||
.aip-msg.ai p{margin:0 0 6px}
|
||
.aip-msg.ai p:last-child{margin-bottom:0}
|
||
/* Anime öneri kartları */
|
||
.aip-cards{display:grid;grid-template-columns:repeat(2,1fr);gap:7px;padding:2px 0}
|
||
.aip-card{
|
||
background:rgba(255,255,255,.04);border:1px solid rgba(184,77,255,.15);
|
||
border-radius:10px;overflow:hidden;cursor:pointer;text-decoration:none;
|
||
display:flex;flex-direction:column;transition:all .18s;
|
||
}
|
||
.aip-card:hover{border-color:rgba(255,45,125,.4);background:rgba(255,45,125,.06);transform:translateY(-2px);box-shadow:0 6px 20px rgba(0,0,0,.3)}
|
||
.aip-card-img{position:relative;aspect-ratio:2/3;background:#0d0d1a;overflow:hidden}
|
||
.aip-card-img img{width:100%;height:100%;object-fit:cover;transition:transform .25s}
|
||
.aip-card:hover .aip-card-img img{transform:scale(1.05)}
|
||
.aip-card-img-ph{width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:rgba(255,255,255,.15);font-size:1.6rem}
|
||
.aip-card-badge{position:absolute;top:4px;left:4px;background:rgba(0,0,0,.7);backdrop-filter:blur(4px);border-radius:5px;padding:2px 6px;font-size:.62rem;font-weight:700;color:rgba(255,255,255,.9)}
|
||
.aip-card-body{padding:7px 8px;flex:1}
|
||
.aip-card-title{font-size:.75rem;font-weight:700;color:var(--text);line-height:1.3;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;margin-bottom:4px}
|
||
.aip-card-meta{font-size:.67rem;color:var(--text3);display:flex;align-items:center;gap:4px;flex-wrap:wrap}
|
||
.aip-card-rating{color:#f59e0b;font-weight:700}
|
||
.aip-card-btns{display:flex;gap:4px;padding:0 7px 7px}
|
||
.aip-card-btn{flex:1;padding:5px 0;border-radius:7px;border:none;cursor:pointer;font-size:.7rem;font-weight:700;text-align:center;text-decoration:none;display:flex;align-items:center;justify-content:center;gap:3px;transition:all .14s}
|
||
.aip-card-btn.watch{background:linear-gradient(135deg,var(--accent3),var(--accent));color:#fff}
|
||
.aip-card-btn.detail{background:rgba(255,255,255,.07);color:var(--text2);border:1px solid rgba(255,255,255,.1)}
|
||
.aip-card-btn:hover{opacity:.85}
|
||
/* Follow-up chips */
|
||
.aip-followup{display:flex;flex-wrap:wrap;gap:5px;padding:2px 0}
|
||
.aip-fu{
|
||
padding:5px 10px;border-radius:999px;font-size:.73rem;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;white-space:nowrap;
|
||
}
|
||
.aip-fu:hover{background:rgba(0,245,255,.12);box-shadow:0 0 10px rgba(0,245,255,.15)}
|
||
/* Typing */
|
||
.aip-typing{display:flex;gap:4px;padding:10px 13px;align-self:flex-start;background:rgba(184,77,255,.08);border:1px solid rgba(184,77,255,.15);border-radius:14px;border-bottom-left-radius:4px}
|
||
.aip-dot{width:6px;height:6px;border-radius:50%;background:var(--accent3);animation:aip-b .9s ease-in-out infinite}
|
||
.aip-dot:nth-child(2){animation-delay:.18s;background:var(--accent)}
|
||
.aip-dot:nth-child(3){animation-delay:.36s;background:var(--accent2)}
|
||
@keyframes aip-b{0%,80%,100%{transform:scale(.55);opacity:.35}40%{transform:scale(1);opacity:1}}
|
||
/* Quick actions */
|
||
.aip-quick{padding:0 12px 10px;display:flex;flex-wrap:wrap;gap:5px;flex-shrink:0}
|
||
.aip-q{
|
||
padding:5px 11px;border-radius:999px;font-size:.74rem;font-weight:600;cursor:pointer;
|
||
background:rgba(184,77,255,.1);border:1px solid rgba(184,77,255,.22);color:var(--accent3);
|
||
transition:all .14s;
|
||
}
|
||
.aip-q:hover{background:rgba(184,77,255,.2);border-color:var(--accent3);box-shadow:0 0 12px rgba(184,77,255,.18)}
|
||
/* Page context badge */
|
||
.aip-ctx-badge{
|
||
margin:0 12px 6px;padding:6px 10px;border-radius:8px;font-size:.72rem;
|
||
background:rgba(0,245,255,.06);border:1px solid rgba(0,245,255,.18);color:var(--accent2);
|
||
display:flex;align-items:center;gap:6px;flex-shrink:0;
|
||
}
|
||
/* Footer */
|
||
.aip-foot{
|
||
padding:10px 12px;display:flex;gap:8px;align-items:flex-end;
|
||
border-top:1px solid rgba(184,77,255,.12);flex-shrink:0;
|
||
background:rgba(0,0,0,.2);
|
||
}
|
||
#ai-inp{
|
||
flex:1;background:rgba(255,255,255,.05);border:1px solid rgba(184,77,255,.22);
|
||
border-radius:10px;padding:9px 12px;color:var(--text);font-size:.84rem;
|
||
font-family:inherit;resize:none;max-height:100px;outline:none;line-height:1.45;
|
||
transition:border-color .16s;scrollbar-width:none;
|
||
}
|
||
#ai-inp:focus{border-color:var(--accent3);box-shadow:0 0 0 2px rgba(184,77,255,.13)}
|
||
#ai-inp::placeholder{color:var(--text3)}
|
||
#ai-send{
|
||
width:38px;height:38px;border-radius:10px;border:none;cursor:pointer;flex-shrink:0;
|
||
background:linear-gradient(135deg,var(--accent3),var(--accent));color:#fff;font-size:.9rem;
|
||
display:flex;align-items:center;justify-content:center;
|
||
transition:transform .14s,box-shadow .16s;box-shadow:0 0 14px rgba(184,77,255,.3);
|
||
}
|
||
#ai-send:hover{transform:scale(1.06);box-shadow:0 0 22px rgba(184,77,255,.5)}
|
||
#ai-send:disabled{opacity:.4;cursor:not-allowed;transform:none}
|
||
@media(max-width:600px){
|
||
#ai-fab{bottom:16px;right:16px;width:52px;height:52px}
|
||
#ai-panel{
|
||
bottom:80px;right:8px;left:8px;width:auto;
|
||
height:min(480px, calc(100dvh - 100px));
|
||
border-radius:16px;
|
||
}
|
||
}
|
||
</style>
|
||
<div id="ai-fab" title="AI Asistan" onclick="toggleAiPanel()">
|
||
<i class="bi bi-stars"></i>
|
||
</div>
|
||
<div id="ai-panel">
|
||
<div class="aip-head">
|
||
<div class="aip-head-icon"><i class="bi bi-cpu-fill"></i></div>
|
||
<div class="aip-head-info">
|
||
<div class="aip-head-title">Animexe AI</div>
|
||
<div class="aip-head-sub"><span class="aip-online-dot"></span> Aktif & hazır</div>
|
||
</div>
|
||
<div class="aip-head-actions">
|
||
<button class="aip-clear" onclick="aiClearChat()" title="Sohbeti temizle"><i class="bi bi-arrow-counterclockwise"></i></button>
|
||
<button class="aip-close" onclick="toggleAiPanel()" title="Kapat"><i class="bi bi-x-lg"></i></button>
|
||
</div>
|
||
</div>
|
||
<div id="aip-ctx-badge" class="aip-ctx-badge" style="display:none">
|
||
<i class="bi bi-eye-fill"></i><span id="aip-ctx-text"></span>
|
||
</div>
|
||
<div class="aip-msgs" id="aip-msgs">
|
||
<div class="aip-msg-wrap ai">
|
||
<div class="aip-msg ai">Merhaba! 👋 Anime önerisi isteyebilir, site hakkında sorular sorabilir ya da izlediğin bölüm hakkında konuşabiliriz. Nasıl yardımcı olabilirim?</div>
|
||
</div>
|
||
</div>
|
||
<div class="aip-quick" id="aip-quick">
|
||
<button class="aip-q" onclick="aiQuick('Şu an ne izlesem?')">🎯 Ne izlesem?</button>
|
||
<button class="aip-q" onclick="aiQuick('Aksiyon anime öner')">⚔️ Aksiyon</button>
|
||
<button class="aip-q" onclick="aiQuick('Romantik anime film öner')">🌸 Romantik film</button>
|
||
<button class="aip-q" onclick="aiQuick('Nasıl üye olabilirim?')">❓ Site yardımı</button>
|
||
<button class="aip-q" onclick="aiQuick('2024\'te çıkan en iyi animeler?')">✨ 2024 animeleri</button>
|
||
</div>
|
||
<div class="aip-foot">
|
||
<textarea id="ai-inp" rows="1" placeholder="Mesaj yaz..." onkeydown="aiKeydown(event)" oninput="autoGrow(this)"></textarea>
|
||
<button id="ai-send" onclick="aiSend()"><i class="bi bi-send-fill"></i></button>
|
||
</div>
|
||
</div>
|
||
<script>
|
||
(function(){
|
||
const CSRF = document.querySelector('meta[name=csrf-token]').content;
|
||
let aiOpen = false, aiLoading = false;
|
||
|
||
// Mesaj geçmişi (sistem mesajları dahil)
|
||
const _ctx = window.USER_WATCH_CTX;
|
||
const aiMsgs = _ctx
|
||
? [{role:'user', content:`[SİSTEM: Kullanıcının son izledikleri: ${_ctx}. Sadece bağlam için kullan, listeyi gösterme.]`},
|
||
{role:'assistant', content:'Anlıyorum, izleme geçmişinizi bağlam olarak kaydettim.'}]
|
||
: [];
|
||
|
||
// Sayfa bağlamını belirle
|
||
function getPageContext(){
|
||
const p = location.pathname;
|
||
const animeTitle = document.querySelector('meta[name="anime-title"]')?.content;
|
||
const epNum = document.querySelector('meta[name="episode-number"]')?.content;
|
||
const seasonNum = document.querySelector('meta[name="season-number"]')?.content;
|
||
if(p.startsWith('/watch/') && animeTitle){
|
||
return `${animeTitle} adlı animeyi izliyor — S${seasonNum||1}E${epNum||1}`;
|
||
}
|
||
if(p.startsWith('/anime/') && animeTitle){
|
||
return `${animeTitle} anime sayfasında`;
|
||
}
|
||
return '';
|
||
}
|
||
|
||
// Sayfa bağlamı badge'ini göster
|
||
const pageCtx = getPageContext();
|
||
if(pageCtx){
|
||
document.getElementById('aip-ctx-badge').style.display = 'flex';
|
||
document.getElementById('aip-ctx-text').textContent = pageCtx;
|
||
}
|
||
|
||
// Basit markdown renderer
|
||
function renderMarkdown(text){
|
||
// Başında/sonunda boşlukları temizle
|
||
text = text.trim();
|
||
// Satırları işle
|
||
const lines = text.split('\n');
|
||
const out = [];
|
||
let inList = false, listTag = '';
|
||
|
||
function closeList(){
|
||
if(inList){ out.push(`</${listTag}>`); inList=false; listTag=''; }
|
||
}
|
||
|
||
for(let i=0; i<lines.length; i++){
|
||
let ln = lines[i];
|
||
// Unordered list
|
||
if(/^[\-\*] (.+)/.test(ln)){
|
||
if(!inList || listTag!=='ul'){ closeList(); out.push('<ul>'); inList=true; listTag='ul'; }
|
||
out.push('<li>'+inlineMd(ln.replace(/^[\-\*] /,''))+'</li>');
|
||
// Ordered list
|
||
} else if(/^\d+\. (.+)/.test(ln)){
|
||
if(!inList || listTag!=='ol'){ closeList(); out.push('<ol>'); inList=true; listTag='ol'; }
|
||
out.push('<li>'+inlineMd(ln.replace(/^\d+\. /,''))+'</li>');
|
||
} else {
|
||
closeList();
|
||
if(ln.trim()===''){
|
||
// blank line → paragraph break
|
||
if(out.length && !out[out.length-1].endsWith('<br>')){
|
||
out.push('<br>');
|
||
}
|
||
} else {
|
||
out.push('<p>'+inlineMd(ln)+'</p>');
|
||
}
|
||
}
|
||
}
|
||
closeList();
|
||
return out.join('');
|
||
}
|
||
|
||
function inlineMd(s){
|
||
s = s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
||
// Bold
|
||
s = s.replace(/\*\*(.+?)\*\*/g,'<b>$1</b>');
|
||
// Italic
|
||
s = s.replace(/\*(.+?)\*/g,'<em>$1</em>');
|
||
// Inline code
|
||
s = s.replace(/`([^`]+)`/g,'<code style="background:rgba(255,255,255,.08);padding:1px 5px;border-radius:4px;font-size:.82em">$1</code>');
|
||
return s;
|
||
}
|
||
|
||
function esc(s){ return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); }
|
||
|
||
function appendMsg(role, html, isHtml){
|
||
const wrap = document.createElement('div');
|
||
wrap.className = 'aip-msg-wrap '+role;
|
||
const el = document.createElement('div');
|
||
el.className = 'aip-msg '+role;
|
||
if(isHtml) el.innerHTML = html;
|
||
else el.textContent = html;
|
||
wrap.appendChild(el);
|
||
document.getElementById('aip-msgs').appendChild(wrap);
|
||
el.scrollIntoView({behavior:'smooth', block:'end'});
|
||
return wrap;
|
||
}
|
||
|
||
function appendAnimeCards(cards){
|
||
if(!cards || !cards.length) return;
|
||
const wrap = document.createElement('div');
|
||
wrap.className = 'aip-msg-wrap ai';
|
||
const grid = document.createElement('div');
|
||
grid.className = 'aip-cards';
|
||
cards.forEach(a=>{
|
||
const typeLabel = a.type==='movie' ? 'Film' : (a.type==='ova' ? 'OVA' : 'Dizi');
|
||
const ratingHtml = a.rating ? `<span class="aip-card-rating">★${parseFloat(a.rating).toFixed(1)}</span>` : '';
|
||
grid.innerHTML += `
|
||
<div class="aip-card">
|
||
<div class="aip-card-img">
|
||
${a.cover
|
||
? `<img src="${esc(a.cover)}" alt="${esc(a.title)}" loading="lazy">`
|
||
: `<div class="aip-card-img-ph"><i class="bi bi-image"></i></div>`}
|
||
<div class="aip-card-badge">${esc(typeLabel)}</div>
|
||
</div>
|
||
<div class="aip-card-body">
|
||
<div class="aip-card-title">${esc(a.title)}</div>
|
||
<div class="aip-card-meta">
|
||
${ratingHtml}
|
||
${a.genres ? `<span>${esc(a.genres)}</span>` : ''}
|
||
</div>
|
||
</div>
|
||
<div class="aip-card-btns">
|
||
<a class="aip-card-btn watch" href="/watch/${esc(a.slug)}/1/1"><i class="bi bi-play-fill"></i>İzle</a>
|
||
<a class="aip-card-btn detail" href="/anime/${esc(a.slug)}"><i class="bi bi-info-circle"></i>Detay</a>
|
||
</div>
|
||
</div>`;
|
||
});
|
||
wrap.appendChild(grid);
|
||
document.getElementById('aip-msgs').appendChild(wrap);
|
||
grid.scrollIntoView({behavior:'smooth', block:'end'});
|
||
}
|
||
|
||
function appendFollowUps(chips){
|
||
if(!chips || !chips.length) return;
|
||
const wrap = document.createElement('div');
|
||
wrap.className = 'aip-msg-wrap ai';
|
||
const row = document.createElement('div');
|
||
row.className = 'aip-followup';
|
||
chips.forEach(c=>{
|
||
const btn = document.createElement('button');
|
||
btn.className = 'aip-fu';
|
||
btn.textContent = c;
|
||
btn.onclick = ()=>{ row.parentElement?.remove(); aiQuick(c); };
|
||
row.appendChild(btn);
|
||
});
|
||
wrap.appendChild(row);
|
||
document.getElementById('aip-msgs').appendChild(wrap);
|
||
}
|
||
|
||
// Follow-up chip üretici — mesaj içeriğine göre
|
||
function suggestFollowUps(reply, hasCards){
|
||
const r = reply.toLowerCase();
|
||
const chips = [];
|
||
if(hasCards){
|
||
chips.push('Daha fazla öner', 'Benzer anime var mı?');
|
||
}
|
||
if(r.includes('aksiyon') || r.includes('dövüş')){
|
||
chips.push('Fantezi anime öner', '2024 aksiyon izle');
|
||
} else if(r.includes('roman') || r.includes('sevgi') || r.includes('aşk')){
|
||
chips.push('Hüzünlü romantik öner', 'Komedi romantik göster');
|
||
} else if(r.includes('premium') || r.includes('üyelik') || r.includes('hesap')){
|
||
chips.push('Premium nasıl alınır?', 'Ücretsiz özellikler neler?');
|
||
} else if(!hasCards){
|
||
chips.push('Aksiyon öner', 'Daha fazla anlat');
|
||
}
|
||
return chips.slice(0,3);
|
||
}
|
||
|
||
function showTyping(){
|
||
const el=document.createElement('div');
|
||
el.className='aip-typing';el.id='aip-typing';
|
||
el.innerHTML='<div class="aip-dot"></div><div class="aip-dot"></div><div class="aip-dot"></div>';
|
||
document.getElementById('aip-msgs').appendChild(el);
|
||
el.scrollIntoView({behavior:'smooth',block:'end'});
|
||
}
|
||
|
||
function removeTyping(){
|
||
document.getElementById('aip-typing')?.remove();
|
||
}
|
||
|
||
window.toggleAiPanel=function(){
|
||
aiOpen=!aiOpen;
|
||
document.getElementById('ai-panel').classList.toggle('open',aiOpen);
|
||
if(aiOpen) setTimeout(()=>document.getElementById('ai-inp').focus(),220);
|
||
};
|
||
|
||
window.aiQuick=function(txt){
|
||
document.getElementById('aip-quick').style.display='none';
|
||
document.getElementById('ai-inp').value=txt;
|
||
aiSend();
|
||
};
|
||
|
||
window.autoGrow=function(el){
|
||
el.style.height='auto';
|
||
el.style.height=Math.min(el.scrollHeight,80)+'px';
|
||
};
|
||
|
||
window.aiKeydown=function(e){
|
||
if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();aiSend();}
|
||
};
|
||
|
||
window.aiClearChat=function(){
|
||
aiMsgs.length=0;
|
||
const msgs=document.getElementById('aip-msgs');
|
||
msgs.innerHTML='<div class="aip-msg-wrap ai"><div class="aip-msg ai">Sohbet temizlendi. Nasıl yardımcı olabilirim? 😊</div></div>';
|
||
document.getElementById('aip-quick').style.display='';
|
||
};
|
||
|
||
window.aiSend=async function(){
|
||
if(aiLoading) return;
|
||
const inp=document.getElementById('ai-inp');
|
||
const txt=inp.value.trim();
|
||
if(!txt) return;
|
||
inp.value=''; inp.style.height='auto';
|
||
document.getElementById('aip-quick').style.display='none';
|
||
document.getElementById('ai-send').disabled=true;
|
||
aiLoading=true;
|
||
|
||
appendMsg('user', txt, false);
|
||
aiMsgs.push({role:'user', content:txt});
|
||
|
||
showTyping();
|
||
try{
|
||
const body = {messages: aiMsgs};
|
||
if(pageCtx) body.page_context = pageCtx;
|
||
|
||
const res=await fetch('{{ route("ai.chat") }}',{
|
||
method:'POST',
|
||
headers:{'Content-Type':'application/json','X-CSRF-TOKEN':CSRF},
|
||
body:JSON.stringify(body)
|
||
});
|
||
const data=await res.json();
|
||
removeTyping();
|
||
|
||
const reply = data.reply || data.error || 'Bir hata oluştu.';
|
||
appendMsg('ai', renderMarkdown(reply), true);
|
||
aiMsgs.push({role:'assistant', content:reply});
|
||
|
||
// Anime kartları
|
||
const cards = data.anime_cards || [];
|
||
appendAnimeCards(cards);
|
||
|
||
// Follow-up chips
|
||
appendFollowUps(suggestFollowUps(reply, cards.length > 0));
|
||
|
||
}catch(e){
|
||
removeTyping();
|
||
appendMsg('ai','Bağlantı hatası, lütfen tekrar dene.', false);
|
||
}
|
||
aiLoading=false;
|
||
document.getElementById('ai-send').disabled=false;
|
||
};
|
||
})();
|
||
</script>
|
||
@endauth
|
||
|
||
{{-- ── Sayfa takip sistemi ────────────────────────────────────────────────── --}}
|
||
<script>
|
||
(function(){
|
||
const CSRF = document.querySelector('meta[name="csrf-token"]')?.content || '';
|
||
|
||
function beacon(url, data) {
|
||
// sendBeacon tercih et; fallback fetch
|
||
const body = JSON.stringify(data);
|
||
if (navigator.sendBeacon) {
|
||
const blob = new Blob([body], {type:'application/json'});
|
||
// sendBeacon CSRF header gönderemez, fetch kullan
|
||
}
|
||
fetch(url, {
|
||
method:'POST',
|
||
headers:{'Content-Type':'application/json','X-CSRF-TOKEN':CSRF},
|
||
keepalive:true, body
|
||
}).catch(()=>{});
|
||
}
|
||
|
||
// Sayfa türünü URL'den tespit et
|
||
function detectPageType() {
|
||
const p = location.pathname;
|
||
if (p === '/' || p === '') return 'home';
|
||
if (p.startsWith('/watch/')) return 'player';
|
||
if (p.startsWith('/anime/')) return 'anime';
|
||
if (p.startsWith('/search')) return 'search';
|
||
if (p.startsWith('/ai')) return 'ai';
|
||
if (p.startsWith('/genre/')) return 'genre';
|
||
return 'other';
|
||
}
|
||
|
||
// Anime ID'yi meta tag'den al (player/anime sayfası bunu set eder)
|
||
function getMeta(name) {
|
||
return document.querySelector(`meta[name="${name}"]`)?.content || null;
|
||
}
|
||
|
||
// Sayfa görüntüleme kaydı
|
||
window.addEventListener('load', function() {
|
||
beacon('/track/pageview', {
|
||
page_type: detectPageType(),
|
||
anime_id: getMeta('track-anime-id'),
|
||
episode_id: getMeta('track-episode-id'),
|
||
url: location.pathname + location.search,
|
||
referrer: document.referrer,
|
||
});
|
||
});
|
||
|
||
// Video izleme takibi (player sayfasında tetiklenir)
|
||
window.TrackWatch = function(animeId, episodeId, seasonNum, episodeNum) {
|
||
const vd = document.querySelector('video');
|
||
if (!vd || !animeId) return;
|
||
|
||
let lastReported = 0;
|
||
let trackTimer = null;
|
||
|
||
function sendWatch() {
|
||
const sec = Math.floor(vd.currentTime);
|
||
if (sec === lastReported || sec < 5) return;
|
||
lastReported = sec;
|
||
const total = Math.floor(vd.duration) || 0;
|
||
const pct = total > 0 ? Math.min(100, Math.round(sec / total * 100)) : 0;
|
||
beacon('/track/watch', {
|
||
anime_id: parseInt(animeId),
|
||
episode_id: episodeId ? parseInt(episodeId) : null,
|
||
season_number: parseInt(seasonNum) || 1,
|
||
episode_number: parseInt(episodeNum) || 1,
|
||
seconds: sec,
|
||
total: total,
|
||
percent: pct,
|
||
});
|
||
}
|
||
|
||
// Her 30 saniyede bir gönder
|
||
trackTimer = setInterval(sendWatch, 30000);
|
||
|
||
// Video kapanırken de gönder
|
||
vd.addEventListener('pause', sendWatch);
|
||
document.addEventListener('visibilitychange', function() {
|
||
if (document.hidden) sendWatch();
|
||
});
|
||
window.addEventListener('beforeunload', function() {
|
||
sendWatch();
|
||
clearInterval(trackTimer);
|
||
});
|
||
};
|
||
})();
|
||
</script>
|
||
|
||
{{-- ── Page Transition Loader ──────────────────────────────────────── --}}
|
||
<style>
|
||
#page-loader{
|
||
position:fixed;inset:0;z-index:9999;
|
||
pointer-events:none;
|
||
opacity:0;transition:opacity .2s ease;
|
||
}
|
||
#page-loader.show{ opacity:1;pointer-events:all; }
|
||
|
||
/* Top progress bar */
|
||
#loader-bar{
|
||
position:absolute;top:0;left:0;height:2px;width:0%;
|
||
background:linear-gradient(90deg,var(--accent2),var(--accent),var(--accent3));
|
||
box-shadow:0 0 12px var(--accent2),0 0 24px var(--accent);
|
||
transition:width .4s cubic-bezier(.4,0,.2,1);
|
||
border-radius:0 2px 2px 0;
|
||
}
|
||
#loader-bar::after{
|
||
content:'';position:absolute;right:0;top:50%;transform:translateY(-50%);
|
||
width:80px;height:100%;
|
||
background:linear-gradient(90deg,transparent,rgba(0,245,255,.7));
|
||
filter:blur(4px);
|
||
}
|
||
|
||
/* Center spinner */
|
||
#loader-center{
|
||
position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
|
||
display:flex;flex-direction:column;align-items:center;gap:16px;
|
||
opacity:0;transition:opacity .15s ease .25s;
|
||
}
|
||
#page-loader.show #loader-center{ opacity:1; }
|
||
|
||
.loader-ring{
|
||
width:44px;height:44px;
|
||
border-radius:50%;
|
||
border:2px solid rgba(0,245,255,.1);
|
||
border-top-color:var(--accent2);
|
||
border-right-color:var(--accent);
|
||
animation:loader-spin .7s linear infinite;
|
||
box-shadow:0 0 20px rgba(0,245,255,.15) inset;
|
||
}
|
||
@keyframes loader-spin{ to{ transform:rotate(360deg); } }
|
||
|
||
.loader-dots{
|
||
display:flex;gap:6px;
|
||
}
|
||
.loader-dots span{
|
||
width:5px;height:5px;border-radius:50%;
|
||
background:var(--accent2);
|
||
animation:loader-dot .9s ease-in-out infinite;
|
||
opacity:.3;
|
||
}
|
||
.loader-dots span:nth-child(2){ animation-delay:.15s;background:var(--accent); }
|
||
.loader-dots span:nth-child(3){ animation-delay:.3s;background:var(--accent3); }
|
||
@keyframes loader-dot{
|
||
0%,100%{ opacity:.3;transform:scale(1); }
|
||
50%{ opacity:1;transform:scale(1.4); }
|
||
}
|
||
|
||
/* Page content fade-out on leave */
|
||
#page-content{ transition:opacity .18s ease,transform .18s ease; }
|
||
#page-content.leaving{ opacity:0;transform:translateY(8px); }
|
||
</style>
|
||
|
||
<div id="page-loader">
|
||
<div id="loader-bar"></div>
|
||
<div id="loader-center">
|
||
<div class="loader-ring"></div>
|
||
<div class="loader-dots"><span></span><span></span><span></span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
(function(){
|
||
// ── Splash (ilk giriş) ──────────────────────────────────────────
|
||
const splash = document.getElementById('splash');
|
||
function hideSplash(){
|
||
if (!splash) return;
|
||
splash.classList.add('done');
|
||
setTimeout(()=>{ if(splash.parentNode) splash.parentNode.removeChild(splash); }, 400);
|
||
}
|
||
// Sayfa hazır olunca hemen kapat, en fazla 2sn bekle
|
||
const splashTimeout = setTimeout(hideSplash, 2000);
|
||
function tryHideSplash(){
|
||
clearTimeout(splashTimeout);
|
||
hideSplash();
|
||
}
|
||
if (document.readyState === 'complete') tryHideSplash();
|
||
else window.addEventListener('load', tryHideSplash);
|
||
// back-forward cache: splash DOM yoksa sorun yok (removeChild ile silindi)
|
||
window.addEventListener('pageshow', function(e){ if(e.persisted) hideSplash(); });
|
||
})();
|
||
|
||
(function(){
|
||
const loader = document.getElementById('page-loader');
|
||
const bar = document.getElementById('loader-bar');
|
||
const content = document.getElementById('page-content');
|
||
if (!loader) return;
|
||
|
||
let barTimer, hideTimer;
|
||
|
||
function showLoader(){
|
||
clearTimeout(hideTimer);
|
||
loader.classList.add('show');
|
||
bar.style.width = '0%';
|
||
// Progress bar animasyonu: hızlı başlar, 85'de yavaşlar
|
||
requestAnimationFrame(()=>{
|
||
bar.style.width = '45%';
|
||
barTimer = setTimeout(()=>{ bar.style.width = '75%'; }, 300);
|
||
setTimeout(()=>{ bar.style.width = '88%'; }, 700);
|
||
});
|
||
if (content) content.classList.add('leaving');
|
||
}
|
||
|
||
function hideLoader(){
|
||
clearTimeout(barTimer);
|
||
bar.style.transition = 'width .15s ease';
|
||
bar.style.width = '100%';
|
||
setTimeout(()=>{
|
||
loader.classList.remove('show');
|
||
bar.style.transition = 'width .4s cubic-bezier(.4,0,.2,1)';
|
||
bar.style.width = '0%';
|
||
if (content) content.classList.remove('leaving');
|
||
}, 200);
|
||
}
|
||
|
||
// Link click'te loader göster (aynı sekme, dış link değil, anchor değil)
|
||
document.addEventListener('click', function(e){
|
||
if (!(e.target instanceof Element)) return;
|
||
const a = e.target.closest('a');
|
||
if (!a) return;
|
||
const href = a.getAttribute('href');
|
||
if (!href || href.startsWith('#') || href.startsWith('javascript') || href.startsWith('mailto')) return;
|
||
if (a.target === '_blank') return;
|
||
try {
|
||
const url = new URL(href, location.href);
|
||
if (url.origin !== location.origin) return;
|
||
if (url.pathname === location.pathname && url.search === location.search) return;
|
||
} catch(err){ return; }
|
||
showLoader();
|
||
});
|
||
|
||
// Form submit'te loader göster (sadece gerçek sayfa yükleyen formlar için)
|
||
document.addEventListener('submit', function(e){
|
||
if (e.defaultPrevented) return;
|
||
const f = e.target;
|
||
if (f.method && f.method.toLowerCase() === 'get') showLoader();
|
||
});
|
||
|
||
// Sayfa yüklenince gizle
|
||
window.addEventListener('pageshow', function(e){
|
||
hideLoader();
|
||
// back-forward cache'den geliyorsa loader'ı da kapat
|
||
if (e.persisted) hideLoader();
|
||
});
|
||
window.addEventListener('load', hideLoader);
|
||
|
||
// Geri/ileri buton
|
||
window.addEventListener('popstate', showLoader);
|
||
})();
|
||
</script>
|
||
|
||
{{-- ── Global Kullanıcı Kart Popup ─────────────────────────────── --}}
|
||
<style>
|
||
#ucard-popup{
|
||
position:fixed;z-index:9990;
|
||
background:linear-gradient(160deg,rgba(10,10,22,.98),rgba(6,6,14,.99));
|
||
border:1px solid rgba(255,255,255,.12);
|
||
border-radius:16px;padding:16px;
|
||
width:230px;
|
||
box-shadow:0 20px 60px rgba(0,0,0,.7),0 0 40px rgba(0,0,0,.4);
|
||
pointer-events:auto;
|
||
opacity:0;transform:scale(.94);
|
||
transition:opacity .16s,transform .16s;
|
||
}
|
||
#ucard-popup.show{opacity:1;transform:scale(1)}
|
||
.ucard-top{display:flex;align-items:center;gap:10px;margin-bottom:12px}
|
||
.ucard-ava{
|
||
width:44px;height:44px;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:.95rem;font-weight:800;color:#fff;text-decoration:none;
|
||
}
|
||
.ucard-ava img{width:100%;height:100%;object-fit:cover}
|
||
.ucard-info{flex:1;min-width:0}
|
||
.ucard-name{font-size:.88rem;font-weight:800;color:#fff;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||
.ucard-user{font-size:.72rem;color:rgba(255,255,255,.35);margin-top:1px}
|
||
.ucard-stats{display:flex;gap:14px;margin-bottom:12px}
|
||
.ucard-stat{text-align:center}
|
||
.ucard-stat-n{font-size:.88rem;font-weight:800;color:#fff}
|
||
.ucard-stat-l{font-size:.62rem;color:rgba(255,255,255,.35)}
|
||
.ucard-actions{display:flex;gap:6px}
|
||
.ucard-btn{
|
||
flex:1;padding:7px 0;border-radius:9px;border:none;cursor:pointer;
|
||
font-size:.75rem;font-weight:700;font-family:inherit;
|
||
display:flex;align-items:center;justify-content:center;gap:5px;
|
||
transition:all .15s;text-decoration:none;
|
||
}
|
||
.ucard-btn-follow{background:var(--accent2);color:#05050e}
|
||
.ucard-btn-follow:hover{background:#00d4de}
|
||
.ucard-btn-follow.following{background:rgba(255,255,255,.1);color:rgba(255,255,255,.6);border:1px solid rgba(255,255,255,.15)}
|
||
.ucard-btn-follow.following:hover{background:rgba(255,80,80,.15);color:#ff6b6b;border-color:rgba(255,80,80,.3)}
|
||
.ucard-btn-msg{background:rgba(255,255,255,.08);color:rgba(255,255,255,.7);border:1px solid rgba(255,255,255,.12)}
|
||
.ucard-btn-msg:hover{background:rgba(255,255,255,.14);color:#fff}
|
||
.ucard-profile-link{display:block;text-align:center;font-size:.7rem;color:rgba(255,255,255,.3);margin-top:9px;text-decoration:none;transition:color .15s}
|
||
.ucard-profile-link:hover{color:rgba(255,255,255,.7)}
|
||
#ucard-popup .ucard-loading{text-align:center;padding:12px 0;color:rgba(255,255,255,.3);font-size:.8rem}
|
||
</style>
|
||
<div id="ucard-popup"></div>
|
||
<script>
|
||
(function(){
|
||
const popup = document.getElementById('ucard-popup');
|
||
if (!popup) return;
|
||
|
||
let hideTimer = null;
|
||
let currentUid = null;
|
||
let cache = {};
|
||
const IS_LOGGED = {{ auth()->check() ? 'true' : 'false' }};
|
||
const CSRF = document.querySelector('meta[name=csrf-token]')?.content || '';
|
||
|
||
function showPopup(uid, anchor) {
|
||
clearTimeout(hideTimer);
|
||
if (currentUid === uid && popup.classList.contains('show')) return;
|
||
currentUid = uid;
|
||
|
||
popup.classList.remove('show');
|
||
popup.innerHTML = '<div class="ucard-loading"><i class="bi bi-arrow-repeat" style="animation:spin .8s linear infinite;display:inline-block"></i> Yükleniyor…</div>';
|
||
positionPopup(anchor);
|
||
popup.classList.add('show');
|
||
|
||
if (cache[uid]) { renderCard(cache[uid]); return; }
|
||
|
||
fetch(`/u/${uid}/card`, { headers: { 'Accept': 'application/json', 'X-CSRF-TOKEN': CSRF } })
|
||
.then(r => r.json())
|
||
.then(d => { cache[uid] = d; if (currentUid == uid) renderCard(d); })
|
||
.catch(() => { popup.classList.remove('show'); });
|
||
}
|
||
|
||
function positionPopup(el) {
|
||
const r = el.getBoundingClientRect();
|
||
const pw = 230, margin = 8;
|
||
let left = r.right + margin;
|
||
let top = r.top;
|
||
if (left + pw > window.innerWidth - 8) left = r.left - pw - margin;
|
||
if (left < 8) left = 8;
|
||
if (top + 220 > window.innerHeight) top = window.innerHeight - 228;
|
||
if (top < 8) top = 8;
|
||
popup.style.left = left + 'px';
|
||
popup.style.top = top + 'px';
|
||
}
|
||
|
||
function renderCard(d) {
|
||
const ava = d.avatar
|
||
? `<img src="${esc(d.avatar)}" alt="${esc(d.name)}">`
|
||
: (d.name||'?').charAt(0).toUpperCase();
|
||
const userTag = d.username ? `<div class="ucard-user">@${esc(d.username)}</div>` : '';
|
||
const followBtn = IS_LOGGED && !d.is_me && d.follow_url
|
||
? `<button class="ucard-btn ucard-btn-follow${d.is_following?' following':''}" data-follow-url="${esc(d.follow_url)}" onclick="ucardFollow(this,${d.id})">${d.is_following?'<i class="bi bi-check2"></i> Takip Ediliyor':'<i class="bi bi-person-plus"></i> Takip Et'}</button>`
|
||
: '';
|
||
const msgBtn = IS_LOGGED && !d.is_me && d.msg_url
|
||
? `<form method="POST" action="${esc(d.msg_url)}" style="flex:1"><input type="hidden" name="_token" value="${CSRF}"><button type="submit" class="ucard-btn ucard-btn-msg" style="width:100%"><i class="bi bi-chat-dots"></i> Mesaj</button></form>`
|
||
: '';
|
||
popup.innerHTML = `
|
||
<div class="ucard-top">
|
||
<a href="${esc(d.profile_url)}" class="ucard-ava">${ava}</a>
|
||
<div class="ucard-info">
|
||
<div class="ucard-name">${esc(d.name)}</div>
|
||
${userTag}
|
||
</div>
|
||
</div>
|
||
<div class="ucard-stats">
|
||
<div class="ucard-stat"><div class="ucard-stat-n">${d.followers}</div><div class="ucard-stat-l">Takipçi</div></div>
|
||
<div class="ucard-stat"><div class="ucard-stat-n">${d.following}</div><div class="ucard-stat-l">Takip</div></div>
|
||
</div>
|
||
<div class="ucard-actions">${followBtn}${msgBtn}</div>
|
||
<a href="${esc(d.profile_url)}" class="ucard-profile-link">Profilini gör <i class="bi bi-arrow-right"></i></a>
|
||
`;
|
||
}
|
||
|
||
function esc(s) {
|
||
return String(s||'').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||
}
|
||
|
||
window.ucardFollow = async function(btn, uid) {
|
||
try {
|
||
const url = btn.dataset.followUrl;
|
||
const r = await fetch(url, { method:'POST', headers:{'X-CSRF-TOKEN':CSRF,'Accept':'application/json'} });
|
||
const d = await r.json();
|
||
const following = d.following;
|
||
btn.className = `ucard-btn ucard-btn-follow${following?' following':''}`;
|
||
btn.innerHTML = following ? '<i class="bi bi-check2"></i> Takip Ediliyor' : '<i class="bi bi-person-plus"></i> Takip Et';
|
||
if (cache[uid]) cache[uid].is_following = following;
|
||
} catch(e) {}
|
||
};
|
||
|
||
// Dismiss popup
|
||
popup.addEventListener('mouseenter', () => clearTimeout(hideTimer));
|
||
popup.addEventListener('mouseleave', () => { hideTimer = setTimeout(() => popup.classList.remove('show'), 300); currentUid = null; });
|
||
|
||
document.addEventListener('click', function(e) {
|
||
if (!(e.target instanceof Element)) return;
|
||
// Click on [data-uid]
|
||
const el = e.target.closest('[data-uid]');
|
||
if (el) {
|
||
// Anchor links with href should navigate normally (don't intercept)
|
||
if (el.tagName === 'A' && el.href) return;
|
||
e.preventDefault();
|
||
const uid = el.dataset.uid;
|
||
if (popup.classList.contains('show') && currentUid == uid) {
|
||
popup.classList.remove('show'); currentUid = null;
|
||
} else {
|
||
showPopup(uid, el);
|
||
}
|
||
return;
|
||
}
|
||
// Click outside popup
|
||
if (!popup.contains(e.target)) {
|
||
popup.classList.remove('show'); currentUid = null;
|
||
}
|
||
});
|
||
|
||
// Hover on [data-uid] (desktop)
|
||
document.addEventListener('mouseover', function(e) {
|
||
if (!(e.target instanceof Element)) return;
|
||
const el = e.target.closest('[data-uid]');
|
||
if (!el) return;
|
||
clearTimeout(hideTimer);
|
||
hideTimer = setTimeout(() => showPopup(el.dataset.uid, el), 350);
|
||
});
|
||
document.addEventListener('mouseout', function(e) {
|
||
if (!(e.target instanceof Element)) return;
|
||
const el = e.target.closest('[data-uid]');
|
||
if (!el) return;
|
||
clearTimeout(hideTimer);
|
||
hideTimer = setTimeout(() => {
|
||
if (!popup.matches(':hover')) { popup.classList.remove('show'); currentUid = null; }
|
||
}, 250);
|
||
});
|
||
})();
|
||
</script>
|
||
<style>
|
||
@keyframes spin{from{transform:rotate(0)}to{transform:rotate(360deg)}}
|
||
</style>
|
||
|
||
<script>
|
||
/* ══════════════════════════════════════════════════════
|
||
ANIMEXE PREMIUM GLOBAL JS
|
||
══════════════════════════════════════════════════════ */
|
||
(function() {
|
||
'use strict';
|
||
|
||
// ── Scroll Progress Bar ─────────────────────────────
|
||
const progressEl = document.getElementById('scroll-progress');
|
||
const scrollTopBtn = document.getElementById('scroll-top');
|
||
const topnav = document.getElementById('topnav');
|
||
|
||
function onScroll() {
|
||
const scrollable = document.documentElement.scrollHeight - window.innerHeight;
|
||
if (progressEl && scrollable > 0) {
|
||
progressEl.style.width = Math.min(100, (window.scrollY / scrollable) * 100) + '%';
|
||
}
|
||
if (scrollTopBtn) scrollTopBtn.classList.toggle('show', window.scrollY > 420);
|
||
if (topnav) topnav.classList.toggle('scrolled', window.scrollY > 50);
|
||
}
|
||
window.addEventListener('scroll', onScroll, { passive: true });
|
||
|
||
// Scroll to top
|
||
if (scrollTopBtn) {
|
||
scrollTopBtn.addEventListener('click', () => window.scrollTo({ top: 0, behavior: 'smooth' }));
|
||
}
|
||
|
||
// ── Scroll Reveal System ─────────────────────────────
|
||
function initReveal() {
|
||
// Auto-add reveal class to home sections and section headers
|
||
document.querySelectorAll('.home-section').forEach((el, i) => {
|
||
if (!el.classList.contains('reveal')) el.classList.add('reveal');
|
||
});
|
||
document.querySelectorAll('.hs-hdr').forEach((el, i) => {
|
||
if (!el.classList.contains('reveal')) {
|
||
el.classList.add('reveal');
|
||
el.classList.add('reveal-d' + Math.min(i % 3 + 1, 5));
|
||
}
|
||
});
|
||
document.querySelectorAll('.promo-banner').forEach(el => {
|
||
if (!el.classList.contains('reveal')) el.classList.add('reveal');
|
||
});
|
||
|
||
const observer = new IntersectionObserver((entries) => {
|
||
entries.forEach(entry => {
|
||
if (entry.isIntersecting) {
|
||
entry.target.classList.add('visible');
|
||
observer.unobserve(entry.target);
|
||
}
|
||
});
|
||
}, { threshold: 0.08, rootMargin: '0px 0px -30px 0px' });
|
||
|
||
document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
|
||
}
|
||
|
||
// Run after DOM is ready
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('DOMContentLoaded', initReveal);
|
||
} else {
|
||
initReveal();
|
||
}
|
||
|
||
// ── Card hover magnetic tilt (desktop) ─────────────
|
||
if (!('ontouchstart' in window)) {
|
||
document.addEventListener('mousemove', function(e) {
|
||
if (!(e.target instanceof Element)) return;
|
||
const card = e.target.closest('.pc, .tpc, .sl-card, .mv-card');
|
||
if (!card) return;
|
||
const rect = card.getBoundingClientRect();
|
||
const cx = rect.left + rect.width / 2;
|
||
const cy = rect.top + rect.height / 2;
|
||
const dx = (e.clientX - cx) / (rect.width / 2);
|
||
const dy = (e.clientY - cy) / (rect.height / 2);
|
||
card.style.transform = `translateY(-4px) perspective(600px) rotateY(${dx * 4}deg) rotateX(${-dy * 3}deg)`;
|
||
});
|
||
document.addEventListener('mouseleave', function(e) {
|
||
if (!(e.target instanceof Element)) return;
|
||
const card = e.target.closest('.pc, .tpc, .sl-card, .mv-card');
|
||
if (card) card.style.transform = '';
|
||
}, true);
|
||
}
|
||
|
||
// ── Splash screen dismiss ───────────────────────────
|
||
const splash = document.getElementById('splash');
|
||
if (splash) {
|
||
window.addEventListener('load', () => {
|
||
setTimeout(() => splash.classList.add('done'), 300);
|
||
});
|
||
// Fallback: max 2.5s
|
||
setTimeout(() => splash && splash.classList.add('done'), 2500);
|
||
}
|
||
|
||
// ── Button ripple effect ────────────────────────────
|
||
document.addEventListener('click', function(e) {
|
||
if (!(e.target instanceof Element)) return;
|
||
const btn = e.target.closest('.h-play-btn, .btn-solid, .promo-cta, .btn-ghost');
|
||
if (!btn) return;
|
||
const rect = btn.getBoundingClientRect();
|
||
const ripple = document.createElement('span');
|
||
const size = Math.max(rect.width, rect.height) * 1.8;
|
||
ripple.style.cssText = `
|
||
position:absolute;width:${size}px;height:${size}px;border-radius:50%;
|
||
background:rgba(255,255,255,.22);pointer-events:none;
|
||
left:${e.clientX - rect.left - size/2}px;
|
||
top:${e.clientY - rect.top - size/2}px;
|
||
transform:scale(0);animation:ripple-burst .55s ease-out forwards;
|
||
`;
|
||
if (getComputedStyle(btn).position === 'static') btn.style.position = 'relative';
|
||
btn.appendChild(ripple);
|
||
ripple.addEventListener('animationend', () => ripple.remove());
|
||
});
|
||
|
||
// ── Stats counter animation ─────────────────────────
|
||
function animateCount(el) {
|
||
const target = parseFloat(el.dataset.count || el.textContent.replace(/\D/g,''));
|
||
if (!target || isNaN(target)) return;
|
||
const duration = 900;
|
||
const start = performance.now();
|
||
const isFloat = String(target).includes('.');
|
||
function step(now) {
|
||
const progress = Math.min((now - start) / duration, 1);
|
||
const eased = 1 - Math.pow(1 - progress, 3);
|
||
const val = eased * target;
|
||
el.textContent = isFloat ? val.toFixed(1) : Math.round(val).toLocaleString('tr-TR');
|
||
if (progress < 1) requestAnimationFrame(step);
|
||
}
|
||
requestAnimationFrame(step);
|
||
}
|
||
|
||
const countObserver = new IntersectionObserver((entries) => {
|
||
entries.forEach(entry => {
|
||
if (entry.isIntersecting && !entry.target.dataset.counted) {
|
||
entry.target.dataset.counted = '1';
|
||
animateCount(entry.target);
|
||
}
|
||
});
|
||
}, { threshold: 0.5 });
|
||
|
||
document.querySelectorAll('[data-count]').forEach(el => countObserver.observe(el));
|
||
|
||
})();
|
||
</script>
|
||
|
||
<style>
|
||
@keyframes ripple-burst{
|
||
to{transform:scale(1);opacity:0}
|
||
}
|
||
</style>
|
||
|
||
{{-- ── Global Toast Notification System ──────────────────────── --}}
|
||
<style>
|
||
#toast-container{
|
||
position:fixed;bottom:24px;left:50%;transform:translateX(-50%);
|
||
z-index:99999;display:flex;flex-direction:column;gap:8px;
|
||
align-items:center;pointer-events:none;
|
||
}
|
||
.gtoast{
|
||
display:flex;align-items:center;gap:10px;
|
||
padding:11px 18px;border-radius:12px;
|
||
background:rgba(14,14,28,.96);
|
||
border:1px solid rgba(255,255,255,.12);
|
||
backdrop-filter:blur(16px);
|
||
box-shadow:0 8px 32px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.04);
|
||
color:var(--text);font-size:.84rem;font-weight:600;
|
||
pointer-events:auto;white-space:nowrap;max-width:min(420px,90vw);
|
||
animation:toast-in .28s cubic-bezier(.22,1,.36,1) forwards;
|
||
}
|
||
.gtoast.out{ animation:toast-out .25s ease forwards; }
|
||
.gtoast i{ font-size:1rem;flex-shrink:0; }
|
||
.gtoast.success{ border-color:rgba(0,245,255,.3); }
|
||
.gtoast.success i{ color:var(--accent2); }
|
||
.gtoast.error{ border-color:rgba(255,45,125,.3); }
|
||
.gtoast.error i{ color:var(--accent); }
|
||
.gtoast.info{ border-color:rgba(184,77,255,.3); }
|
||
.gtoast.info i{ color:var(--accent3); }
|
||
.gtoast.warning{ border-color:rgba(251,191,36,.3); }
|
||
.gtoast.warning i{ color:#fbbf24; }
|
||
@keyframes toast-in{
|
||
from{ opacity:0;transform:translateY(16px) scale(.94); }
|
||
to{ opacity:1;transform:translateY(0) scale(1); }
|
||
}
|
||
@keyframes toast-out{
|
||
from{ opacity:1;transform:scale(1); }
|
||
to{ opacity:0;transform:scale(.92); }
|
||
}
|
||
@media(max-width:500px){
|
||
#toast-container{ bottom:16px;left:12px;right:12px;transform:none;align-items:stretch; }
|
||
.gtoast{ white-space:normal; }
|
||
}
|
||
</style>
|
||
<div id="toast-container" aria-live="polite"></div>
|
||
<script>
|
||
(function(){
|
||
const ICONS = { success:'bi-check-circle-fill', error:'bi-x-circle-fill', info:'bi-info-circle-fill', warning:'bi-exclamation-triangle-fill' };
|
||
window.showToast = function(msg, type, duration) {
|
||
type = type || 'success';
|
||
duration = duration || 3200;
|
||
const c = document.getElementById('toast-container');
|
||
if (!c) return;
|
||
const t = document.createElement('div');
|
||
t.className = 'gtoast ' + type;
|
||
t.innerHTML = '<i class="bi ' + (ICONS[type]||ICONS.info) + '"></i><span>' + msg + '</span>';
|
||
c.appendChild(t);
|
||
setTimeout(() => {
|
||
t.classList.add('out');
|
||
t.addEventListener('animationend', () => t.remove(), { once: true });
|
||
}, duration);
|
||
};
|
||
})();
|
||
</script>
|
||
|
||
{{-- ═══════════════════════════════════════════════════════════════
|
||
CHAT PANEL JS v2
|
||
═══════════════════════════════════════════════════════════════ --}}
|
||
@auth
|
||
<script>
|
||
(function(){
|
||
'use strict';
|
||
|
||
const CP_CSRF = document.querySelector('meta[name=csrf-token]')?.content || '';
|
||
const CP_ME_ID = {{ auth()->id() }};
|
||
const CP_MY_NAME = {!! json_encode(auth()->user()->name) !!};
|
||
const CP_MY_AVA = {!! json_encode(auth()->user()->avatar ? \App\Support\MediaUrl::fromStoragePath(auth()->user()->avatar) : null) !!};
|
||
const CP_CONVS_URL = '{{ route("messages.conversations") }}';
|
||
const CP_UPLOAD_URL = '{{ route("messages.upload-image") }}';
|
||
const TENOR_KEY = '{{ env("TENOR_API_KEY","") }}';
|
||
const IS_MOBILE = window.matchMedia('(max-width:900px)').matches;
|
||
|
||
let cpOpen = false;
|
||
let cpConvId = null;
|
||
let cpConvUserId = null;
|
||
let cpLastMsgId = 0;
|
||
let cpPollTimer = null;
|
||
let cpEmojiOpen = false;
|
||
let cpGifOpen = false;
|
||
let cpGifTimer = null;
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
PANEL OPEN / CLOSE
|
||
════════════════════════════════════════════════════ */
|
||
window.chatPanelToggle = function() {
|
||
cpOpen ? chatPanelClose() : chatPanelOpen();
|
||
};
|
||
|
||
window.chatPanelClose = function() {
|
||
document.getElementById('chat-panel').classList.remove('open');
|
||
document.getElementById('cp-backdrop').classList.remove('on');
|
||
document.body.style.overflow = '';
|
||
cpOpen = false;
|
||
cpStopPoll();
|
||
cpHideEmoji();
|
||
cpHideGif();
|
||
// Restore topnav
|
||
const topnav = document.getElementById('topnav');
|
||
if (topnav) topnav.style.transform = '';
|
||
// Restore mobile bottom nav
|
||
const nav = document.getElementById('mob-bottom-nav');
|
||
if (nav) { nav.style.transform = ''; nav.style.opacity = ''; }
|
||
// Restore Crisp support widget
|
||
if (window.$crisp) try { $crisp.push(['do','chat:show']); } catch(_) {}
|
||
};
|
||
|
||
function chatPanelOpen() {
|
||
document.getElementById('chat-panel').classList.add('open');
|
||
document.getElementById('cp-backdrop').classList.add('on');
|
||
document.body.style.overflow = 'hidden';
|
||
cpOpen = true;
|
||
// Hide topnav (site header)
|
||
const topnav = document.getElementById('topnav');
|
||
if (topnav) topnav.style.transform = 'translateY(-100%)';
|
||
// Hide mobile bottom nav
|
||
const nav = document.getElementById('mob-bottom-nav');
|
||
if (nav) { nav.style.transform = 'translateY(100%)'; nav.style.opacity = '0'; }
|
||
// Hide Crisp support widget
|
||
if (window.$crisp) try { $crisp.push(['do','chat:hide']); } catch(_) {}
|
||
cpShowList();
|
||
cpLoadConvs();
|
||
}
|
||
|
||
document.addEventListener('keydown', e => { if (e.key === 'Escape' && cpOpen) chatPanelClose(); });
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
LIST / THREAD SWITCH
|
||
════════════════════════════════════════════════════ */
|
||
function cpShowList() {
|
||
const list = document.getElementById('cp-list');
|
||
const thread = document.getElementById('cp-thread');
|
||
list.style.display = 'flex';
|
||
thread.classList.remove('active');
|
||
cpStopPoll();
|
||
cpConvId = null;
|
||
cpConvUserId = null;
|
||
}
|
||
window.cpShowList = cpShowList;
|
||
|
||
function cpShowThread() {
|
||
document.getElementById('cp-list').style.display = 'none';
|
||
document.getElementById('cp-thread').classList.add('active');
|
||
}
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
LOAD CONVERSATIONS
|
||
════════════════════════════════════════════════════ */
|
||
async function cpLoadConvs() {
|
||
const el = document.getElementById('cp-convs');
|
||
el.innerHTML = '<div class="cp-loading"><i class="bi bi-hourglass" style="font-size:1.2rem;display:block;margin-bottom:6px;opacity:.3"></i>Yükleniyor…</div>';
|
||
try {
|
||
const r = await fetch(CP_CONVS_URL, { headers: { 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF } });
|
||
const convs = await r.json();
|
||
if (!convs.length) {
|
||
el.innerHTML = '<div class="cp-empty"><i class="bi bi-chat-square-dots"></i>Henüz mesajın yok.</div>';
|
||
return;
|
||
}
|
||
el.innerHTML = '';
|
||
convs.forEach(c => {
|
||
const convId = c.conv_id ?? c.id;
|
||
const letter = (c.name || '?').charAt(0).toUpperCase();
|
||
const ava = c.avatar
|
||
? `<div class="cp-conv-ava"><img src="${escH(c.avatar)}" alt=""></div>`
|
||
: `<div class="cp-conv-ava">${escH(letter)}</div>`;
|
||
|
||
let preview = '';
|
||
if (!c.last_preview) {
|
||
preview = '<em style="color:rgba(255,255,255,.2)">Henüz mesaj yok</em>';
|
||
} else if (c.last_preview.startsWith('IMAGE::')) {
|
||
preview = '📷 Fotoğraf';
|
||
} else if (c.last_preview.startsWith('GIF::')) {
|
||
preview = '🎞 GIF';
|
||
} else {
|
||
preview = escH(c.last_preview);
|
||
}
|
||
const badge = c.unread > 0 ? `<span class="cp-unread-badge">${c.unread > 9 ? '9+' : c.unread}</span>` : '';
|
||
const time = c.time ? `<span class="cp-conv-time">${escH(c.time)}</span>` : '';
|
||
|
||
// data-* ile data taşı — JSON.stringify double-quote HTML attribute'u kırar
|
||
const item = document.createElement('div');
|
||
item.className = 'cp-conv-item' + (c.unread > 0 ? ' unread' : '');
|
||
item.dataset.convId = convId;
|
||
item.dataset.userId = c.id || '';
|
||
item.dataset.name = c.name || '';
|
||
item.dataset.avatar = c.avatar || '';
|
||
item.innerHTML = `${ava}
|
||
<div class="cp-conv-body">
|
||
<div class="cp-conv-name">${escH(c.name || 'Kullanıcı')}</div>
|
||
<div class="cp-conv-preview">${preview}</div>
|
||
</div>
|
||
<div class="cp-conv-meta">${time}${badge}</div>`;
|
||
item.addEventListener('click', () => {
|
||
cpOpenThread(item.dataset.userId, item.dataset.name, item.dataset.avatar || null, item.dataset.convId);
|
||
});
|
||
el.appendChild(item);
|
||
});
|
||
} catch(e) {
|
||
el.innerHTML = '<div class="cp-empty">Yüklenemedi.</div>';
|
||
const btn = document.createElement('button');
|
||
btn.textContent = 'Tekrar dene';
|
||
btn.style.cssText = 'color:var(--accent2);background:none;border:none;cursor:pointer;font-size:.84rem;display:block;margin:8px auto';
|
||
btn.onclick = cpLoadConvs;
|
||
el.appendChild(btn);
|
||
}
|
||
}
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
OPEN THREAD
|
||
════════════════════════════════════════════════════ */
|
||
window.cpOpenThread = async function(userId, name, avatar, convId) {
|
||
cpConvId = convId;
|
||
cpConvUserId = userId;
|
||
cpLastMsgId = 0;
|
||
cpHideEmoji();
|
||
cpHideGif();
|
||
|
||
document.getElementById('cp-t-name').textContent = name || 'Kullanıcı';
|
||
document.getElementById('cp-t-fulllink').href = `/messages/${convId}`;
|
||
|
||
// Store userId for call button
|
||
const callBtn = document.getElementById('cp-t-call-btn');
|
||
if (callBtn) callBtn.dataset.userId = userId;
|
||
|
||
const avaEl = document.getElementById('cp-t-ava');
|
||
if (avatar) {
|
||
avaEl.innerHTML = `<img src="${escH(avatar)}" alt="">`;
|
||
} else {
|
||
avaEl.innerHTML = '';
|
||
avaEl.textContent = (name || '?').charAt(0).toUpperCase();
|
||
}
|
||
|
||
document.getElementById('cp-msgs').innerHTML = '<div class="cp-loading">Yükleniyor…</div>';
|
||
cpShowThread();
|
||
|
||
try {
|
||
const r = await fetch(`/messages/${convId}/poll?after=0`, {
|
||
headers: { 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF }
|
||
});
|
||
const d = await r.json();
|
||
const msgsEl = document.getElementById('cp-msgs');
|
||
msgsEl.innerHTML = '';
|
||
if (!d.messages || !d.messages.length) {
|
||
msgsEl.innerHTML = '<div class="cp-loading" style="padding:30px 20px;color:rgba(255,255,255,.2)">İlk mesajı sen gönder! 👋</div>';
|
||
} else {
|
||
d.messages.forEach(m => cpAppendMsg(m));
|
||
cpLastMsgId = d.messages[d.messages.length - 1].id;
|
||
}
|
||
cpScrollBottom(true);
|
||
cpUpdateBadge(0);
|
||
} catch(e) {}
|
||
|
||
cpStartPoll();
|
||
setTimeout(() => document.getElementById('cp-textarea')?.focus(), 120);
|
||
};
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
APPEND MESSAGE
|
||
════════════════════════════════════════════════════ */
|
||
function cpAppendMsg(m) {
|
||
if (document.querySelector(`.cpm[data-id="${m.id}"]`)) return;
|
||
const isMine = m.user_id === CP_ME_ID;
|
||
const el = document.createElement('div');
|
||
el.className = 'cpm ' + (isMine ? 'mine' : 'theirs');
|
||
el.dataset.id = m.id;
|
||
|
||
let content = '';
|
||
const body = m.body || '';
|
||
|
||
if (body.startsWith('ANIMESHARE::')) {
|
||
try {
|
||
const sd = JSON.parse(body.slice(12));
|
||
const url = `/watch/${sd.slug}/${sd.s}/${sd.e}${sd.ts > 0 ? '?t=' + sd.ts : ''}`;
|
||
const img = sd.cover ? `<img src="${escH(sd.cover)}" loading="lazy" alt="">` : '';
|
||
content = `<a href="${escH(url)}" class="cp-share-card">
|
||
<div class="cp-share-img">${img}</div>
|
||
<div>
|
||
<div class="cp-share-title">${escH(sd.title || '')}</div>
|
||
<div class="cp-share-ep">${sd.s}. Sezon ${sd.e}. Bölüm</div>
|
||
<div class="cp-share-play"><i class="bi bi-play-circle-fill"></i> İzle</div>
|
||
</div>
|
||
</a>`;
|
||
} catch(_) { content = `<div class="cpm-bubble">${escH(body)}</div>`; }
|
||
} else if (body.startsWith('IMAGE::')) {
|
||
const url = body.slice(7);
|
||
content = `<img src="${escH(url)}" class="cpm-img" loading="lazy" alt="Resim" onclick="window.open('${escH(url)}','_blank')">`;
|
||
} else if (body.startsWith('GIF::')) {
|
||
const url = body.slice(5);
|
||
content = `<img src="${escH(url)}" class="cpm-gif" loading="lazy" alt="GIF">`;
|
||
} else {
|
||
content = `<div class="cpm-bubble">${escH(body)}</div>`;
|
||
}
|
||
|
||
const avaHtml = !isMine
|
||
? (m.avatar
|
||
? `<div class="cpm-ava"><img src="${escH(m.avatar)}" alt=""></div>`
|
||
: `<div class="cpm-ava">${escH((m.name || '?').charAt(0).toUpperCase())}</div>`)
|
||
: '';
|
||
|
||
el.innerHTML = avaHtml + `<div>${content}</div><span class="cpm-time">${escH(m.created_at || '')}</span>`;
|
||
document.getElementById('cp-msgs').appendChild(el);
|
||
}
|
||
|
||
function cpScrollBottom(force = false) {
|
||
const el = document.getElementById('cp-msgs');
|
||
if (!el) return;
|
||
const near = el.scrollHeight - el.scrollTop - el.clientHeight < 200;
|
||
if (force || near) el.scrollTop = el.scrollHeight;
|
||
}
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
SEND TEXT
|
||
════════════════════════════════════════════════════ */
|
||
window.cpSend = async function() {
|
||
if (!cpConvId) return;
|
||
const ta = document.getElementById('cp-textarea');
|
||
const btn = document.getElementById('cp-send-btn');
|
||
const text = ta.value.trim();
|
||
if (!text) return;
|
||
|
||
ta.value = '';
|
||
ta.style.height = 'auto';
|
||
btn.disabled = true;
|
||
|
||
try {
|
||
const r = await fetch(`/messages/${cpConvId}/send`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF },
|
||
body: JSON.stringify({ body: text }),
|
||
});
|
||
const d = await r.json();
|
||
cpAppendMsg({ id: d.id, body: d.body, user_id: CP_ME_ID, created_at: d.created_at, avatar: CP_MY_AVA, name: CP_MY_NAME });
|
||
if (d.id > cpLastMsgId) cpLastMsgId = d.id;
|
||
cpScrollBottom(true);
|
||
} catch(_) { ta.value = text; }
|
||
btn.disabled = false;
|
||
};
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
SEND IMAGE
|
||
════════════════════════════════════════════════════ */
|
||
window.cpSendImage = async function(input) {
|
||
const file = input.files[0];
|
||
if (!file || !cpConvId) return;
|
||
input.value = '';
|
||
|
||
try {
|
||
const fd = new FormData();
|
||
fd.append('image', file);
|
||
const r = await fetch(CP_UPLOAD_URL, {
|
||
method: 'POST',
|
||
headers: { 'X-CSRF-TOKEN': CP_CSRF, 'Accept': 'application/json' },
|
||
body: fd,
|
||
});
|
||
const d = await r.json();
|
||
if (!d.url) throw new Error('No URL');
|
||
|
||
const r2 = await fetch(`/messages/${cpConvId}/send`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF },
|
||
body: JSON.stringify({ body: 'IMAGE::' + d.url }),
|
||
});
|
||
const d2 = await r2.json();
|
||
cpAppendMsg({ id: d2.id, body: d2.body, user_id: CP_ME_ID, created_at: d2.created_at, avatar: CP_MY_AVA, name: CP_MY_NAME });
|
||
if (d2.id > cpLastMsgId) cpLastMsgId = d2.id;
|
||
cpScrollBottom(true);
|
||
} catch(e) {
|
||
showToast('Resim gönderilemedi.', 'error');
|
||
}
|
||
};
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
SEND GIF
|
||
════════════════════════════════════════════════════ */
|
||
window.cpSendGif = async function(gifUrl) {
|
||
if (!cpConvId) return;
|
||
cpHideGif();
|
||
try {
|
||
const r = await fetch(`/messages/${cpConvId}/send`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF },
|
||
body: JSON.stringify({ body: 'GIF::' + gifUrl }),
|
||
});
|
||
const d = await r.json();
|
||
cpAppendMsg({ id: d.id, body: d.body, user_id: CP_ME_ID, created_at: d.created_at, avatar: CP_MY_AVA, name: CP_MY_NAME });
|
||
if (d.id > cpLastMsgId) cpLastMsgId = d.id;
|
||
cpScrollBottom(true);
|
||
} catch(_) { showToast('GIF gönderilemedi.', 'error'); }
|
||
};
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
EMOJI PICKER
|
||
════════════════════════════════════════════════════ */
|
||
const EMOJIS = '😀😂😅😊😍🥰😘😎😭😤😡🥺🤔😴🤩🥳😱🙈🙄😏🤗😬😵👍👎❤️🔥💯✨🎉🎊🎮🎬🎵🍕🍜🍣🎃👻🦊🐱🐶🐼🌸🌙⭐🌈💎🚀🏆🎯🔮';
|
||
const emojiArr = [...EMOJIS];
|
||
|
||
function cpInitEmoji() {
|
||
const picker = document.getElementById('cp-emoji-picker');
|
||
if (!picker || picker.dataset.built) return;
|
||
picker.dataset.built = '1';
|
||
const frag = document.createDocumentFragment();
|
||
emojiArr.forEach(em => {
|
||
const btn = document.createElement('button');
|
||
btn.className = 'cp-emoji-btn';
|
||
btn.textContent = em;
|
||
btn.title = em;
|
||
btn.onclick = () => {
|
||
const ta = document.getElementById('cp-textarea');
|
||
const pos = ta.selectionStart;
|
||
ta.value = ta.value.slice(0, pos) + em + ta.value.slice(ta.selectionEnd);
|
||
ta.selectionStart = ta.selectionEnd = pos + em.length;
|
||
ta.dispatchEvent(new Event('input'));
|
||
ta.focus();
|
||
};
|
||
frag.appendChild(btn);
|
||
});
|
||
picker.appendChild(frag);
|
||
}
|
||
|
||
window.cpToggleEmoji = function() {
|
||
cpEmojiOpen = !cpEmojiOpen;
|
||
if (cpEmojiOpen) {
|
||
cpHideGif();
|
||
cpInitEmoji();
|
||
}
|
||
document.getElementById('cp-emoji-picker').classList.toggle('show', cpEmojiOpen);
|
||
document.getElementById('cp-emoji-btn')?.classList.toggle('active', cpEmojiOpen);
|
||
};
|
||
function cpHideEmoji() {
|
||
cpEmojiOpen = false;
|
||
document.getElementById('cp-emoji-picker')?.classList.remove('show');
|
||
document.getElementById('cp-emoji-btn')?.classList.remove('active');
|
||
}
|
||
|
||
/* Show emoji btn on desktop */
|
||
if (!IS_MOBILE) {
|
||
const eb = document.getElementById('cp-emoji-btn');
|
||
if (eb) eb.style.display = '';
|
||
}
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
GIF PICKER (Tenor)
|
||
════════════════════════════════════════════════════ */
|
||
window.cpToggleGif = function() {
|
||
cpGifOpen = !cpGifOpen;
|
||
if (cpGifOpen) {
|
||
cpHideEmoji();
|
||
if (TENOR_KEY) cpSearchGifs('');
|
||
}
|
||
document.getElementById('cp-gif-picker').classList.toggle('show', cpGifOpen);
|
||
document.getElementById('cp-gif-btn')?.classList.toggle('active', cpGifOpen);
|
||
if (cpGifOpen) setTimeout(() => document.getElementById('cp-gif-input')?.focus(), 100);
|
||
};
|
||
function cpHideGif() {
|
||
cpGifOpen = false;
|
||
document.getElementById('cp-gif-picker')?.classList.remove('show');
|
||
document.getElementById('cp-gif-btn')?.classList.remove('active');
|
||
}
|
||
|
||
async function cpSearchGifs(q) {
|
||
const grid = document.getElementById('cp-gif-grid');
|
||
if (!grid) return;
|
||
if (!TENOR_KEY) {
|
||
grid.innerHTML = '<div class="cp-gif-placeholder">TENOR_API_KEY ayarlanmamış.<br>GIF özelliği devre dışı.</div>';
|
||
return;
|
||
}
|
||
grid.innerHTML = '<div class="cp-gif-placeholder">Yükleniyor…</div>';
|
||
try {
|
||
const endpoint = 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(endpoint);
|
||
const d = await r.json();
|
||
const results = d.results || [];
|
||
if (!results.length) { grid.innerHTML = '<div class="cp-gif-placeholder">Sonuç bulunamadı.</div>'; return; }
|
||
grid.innerHTML = results.map(g => {
|
||
const url = g.media_formats?.tinygif?.url || g.media_formats?.gif?.url || '';
|
||
return url ? `<div class="cp-gif-item" onclick="cpSendGif('${escH(url)}')"><img src="${escH(url)}" alt="" loading="lazy"></div>` : '';
|
||
}).filter(Boolean).join('');
|
||
} catch(e) {
|
||
grid.innerHTML = '<div class="cp-gif-placeholder">Yüklenemedi.</div>';
|
||
}
|
||
}
|
||
|
||
document.getElementById('cp-gif-input')?.addEventListener('input', function() {
|
||
clearTimeout(cpGifTimer);
|
||
cpGifTimer = setTimeout(() => cpSearchGifs(this.value.trim()), 400);
|
||
});
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
TEXTAREA EVENTS
|
||
════════════════════════════════════════════════════ */
|
||
document.getElementById('cp-textarea')?.addEventListener('keydown', e => {
|
||
if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); cpSend(); }
|
||
});
|
||
document.getElementById('cp-textarea')?.addEventListener('input', function() {
|
||
this.style.height = 'auto';
|
||
this.style.height = Math.min(this.scrollHeight, 100) + 'px';
|
||
// hide pickers when typing
|
||
if (this.value) { cpHideEmoji(); cpHideGif(); }
|
||
});
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
POLLING (messages)
|
||
════════════════════════════════════════════════════ */
|
||
function cpStartPoll() {
|
||
cpStopPoll();
|
||
cpPollTimer = setInterval(cpPoll, 3000);
|
||
}
|
||
function cpStopPoll() {
|
||
clearInterval(cpPollTimer);
|
||
cpPollTimer = null;
|
||
}
|
||
async function cpPoll() {
|
||
if (!cpConvId || !cpOpen) return;
|
||
try {
|
||
const r = await fetch(`/messages/${cpConvId}/poll?after=${cpLastMsgId}`, {
|
||
headers: { 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF }
|
||
});
|
||
const d = await r.json();
|
||
if (d.messages && d.messages.length) {
|
||
d.messages.forEach(m => {
|
||
if (m.user_id !== CP_ME_ID) {
|
||
cpAppendMsg(m);
|
||
if (m.id > cpLastMsgId) cpLastMsgId = m.id;
|
||
}
|
||
});
|
||
cpScrollBottom();
|
||
}
|
||
} catch(_) {}
|
||
}
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
BADGE UPDATE
|
||
════════════════════════════════════════════════════ */
|
||
function cpUpdateBadge(count) {
|
||
const badge = document.getElementById('cp-nav-badge');
|
||
const icon = document.getElementById('cp-nav-icon');
|
||
if (badge) {
|
||
badge.style.display = count > 0 ? '' : 'none';
|
||
badge.textContent = count > 9 ? '9+' : count;
|
||
}
|
||
if (icon) icon.className = count > 0 ? 'bi bi-chat-dots-fill' : 'bi bi-chat-dots';
|
||
}
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
VOICE CALLS
|
||
════════════════════════════════════════════════════ */
|
||
let vcCallId = null;
|
||
let vcAgoraClient = null;
|
||
let vcCallTimer = null;
|
||
let vcCallSecs = 0;
|
||
let vcPollTimer = null;
|
||
|
||
/* Start outgoing call */
|
||
window.cpStartCall = async function() {
|
||
const callBtn = document.getElementById('cp-t-call-btn');
|
||
const userId = cpConvUserId || (callBtn && callBtn.dataset.userId);
|
||
if (!userId) return;
|
||
try {
|
||
const r = await fetch('/calls/initiate', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF },
|
||
body: JSON.stringify({ callee_id: parseInt(userId) }),
|
||
});
|
||
const d = await r.json();
|
||
if (d.error) { showToast(d.error, 'error'); return; }
|
||
vcCallId = d.call_id;
|
||
vcShowOutgoing(d.callee.name, d.callee.avatar);
|
||
vcMaybeJoinAgora(d.agora_app_id, d.channel_name, d.token, CP_ME_ID);
|
||
vcStartCallPoll();
|
||
} catch(e) { showToast('Arama başlatılamadı.', 'error'); }
|
||
};
|
||
|
||
/* Answer incoming call */
|
||
window.vcAnswer = async function() {
|
||
if (!vcCallId) return;
|
||
try {
|
||
const r = await fetch(`/calls/${vcCallId}/answer`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF },
|
||
});
|
||
const d = await r.json();
|
||
vcShowActive(document.getElementById('call-name-el')?.textContent);
|
||
vcMaybeJoinAgora(d.agora_app_id, d.channel_name, d.token, CP_ME_ID);
|
||
} catch(e) { showToast('Arama cevaplanamadı.', 'error'); }
|
||
};
|
||
|
||
/* Decline */
|
||
window.vcDecline = async function() {
|
||
if (!vcCallId) return;
|
||
const id = vcCallId;
|
||
vcCallId = null;
|
||
vcHideOverlay();
|
||
try {
|
||
await fetch(`/calls/${id}/decline`, {
|
||
method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF },
|
||
});
|
||
} catch(_) {}
|
||
};
|
||
|
||
/* End call */
|
||
window.vcEnd = async function() {
|
||
const id = vcCallId;
|
||
vcCallId = null;
|
||
vcHideOverlay();
|
||
vcHideCallBar();
|
||
vcStopCallPoll();
|
||
vcLeaveAgora();
|
||
if (!id) return;
|
||
try {
|
||
await fetch(`/calls/${id}/end`, {
|
||
method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF },
|
||
});
|
||
} catch(_) {}
|
||
};
|
||
|
||
function vcShowIncoming(name, avatar, callId) {
|
||
vcCallId = callId;
|
||
const avaEl = document.getElementById('call-ava-el');
|
||
const nameEl = document.getElementById('call-name-el');
|
||
const statusEl = document.getElementById('call-status-el');
|
||
const btnsEl = document.getElementById('call-btns-el');
|
||
if (!avaEl) return;
|
||
|
||
if (avatar) {
|
||
avaEl.innerHTML = `<img src="${escH(avatar)}" alt="">`;
|
||
} else {
|
||
avaEl.innerHTML = '';
|
||
avaEl.textContent = (name || '?').charAt(0).toUpperCase();
|
||
}
|
||
if (nameEl) nameEl.textContent = name || 'Bilinmeyen';
|
||
if (statusEl) statusEl.textContent = 'Sesli arama geliyor…';
|
||
if (btnsEl) btnsEl.innerHTML = `
|
||
<button class="call-btn call-btn-decline" onclick="vcDecline()" title="Reddet">
|
||
<i class="bi bi-telephone-x-fill"></i>
|
||
</button>
|
||
<button class="call-btn call-btn-accept" onclick="vcAnswer()" title="Kabul et">
|
||
<i class="bi bi-telephone-fill"></i>
|
||
</button>`;
|
||
|
||
document.getElementById('call-overlay').classList.add('show');
|
||
}
|
||
|
||
function vcShowOutgoing(name, avatar) {
|
||
const avaEl = document.getElementById('call-ava-el');
|
||
const nameEl = document.getElementById('call-name-el');
|
||
const statusEl = document.getElementById('call-status-el');
|
||
const btnsEl = document.getElementById('call-btns-el');
|
||
if (!avaEl) return;
|
||
|
||
if (avatar) avaEl.innerHTML = `<img src="${escH(avatar)}" alt="">`;
|
||
else { avaEl.innerHTML = ''; avaEl.textContent = (name||'?').charAt(0).toUpperCase(); }
|
||
if (nameEl) nameEl.textContent = name || '';
|
||
if (statusEl) statusEl.textContent = 'Aranıyor…';
|
||
if (btnsEl) btnsEl.innerHTML = `
|
||
<button class="call-btn call-btn-decline" onclick="vcEnd()" title="İptal">
|
||
<i class="bi bi-telephone-x-fill"></i>
|
||
</button>`;
|
||
|
||
document.getElementById('call-overlay').classList.add('show');
|
||
}
|
||
|
||
function vcShowActive(name) {
|
||
vcHideOverlay();
|
||
const bar = document.getElementById('call-bar');
|
||
if (!bar) return;
|
||
document.getElementById('call-bar-name').textContent = name || '';
|
||
vcCallSecs = 0;
|
||
clearInterval(vcCallTimer);
|
||
vcCallTimer = setInterval(() => {
|
||
vcCallSecs++;
|
||
const m = String(Math.floor(vcCallSecs / 60)).padStart(2, '0');
|
||
const s = String(vcCallSecs % 60).padStart(2, '0');
|
||
const el = document.getElementById('call-bar-timer');
|
||
if (el) el.textContent = `${m}:${s}`;
|
||
}, 1000);
|
||
bar.classList.add('show');
|
||
}
|
||
|
||
function vcHideOverlay() {
|
||
document.getElementById('call-overlay')?.classList.remove('show');
|
||
}
|
||
function vcHideCallBar() {
|
||
clearInterval(vcCallTimer);
|
||
document.getElementById('call-bar')?.classList.remove('show');
|
||
}
|
||
|
||
/* Agora Web SDK integration */
|
||
function vcMaybeJoinAgora(appId, channel, token, uid) {
|
||
if (!appId || !window.AgoraRTC) return;
|
||
try {
|
||
vcLeaveAgora();
|
||
vcAgoraClient = AgoraRTC.createClient({ mode: 'rtc', codec: 'vp8' });
|
||
vcAgoraClient.join(appId, channel, token || null, uid).then(() => {
|
||
return AgoraRTC.createMicrophoneAudioTrack();
|
||
}).then(track => {
|
||
vcAgoraClient.publish([track]);
|
||
}).catch(e => { console.warn('Agora join failed:', e); });
|
||
} catch(e) {}
|
||
}
|
||
|
||
async function vcLeaveAgora() {
|
||
if (!vcAgoraClient) return;
|
||
try { await vcAgoraClient.leave(); } catch(_) {}
|
||
vcAgoraClient = null;
|
||
}
|
||
|
||
/* Poll for incoming calls + call status changes */
|
||
function vcStartCallPoll() {
|
||
vcStopCallPoll();
|
||
vcPollTimer = setInterval(vcPollCalls, 4000);
|
||
}
|
||
function vcStopCallPoll() {
|
||
clearInterval(vcPollTimer);
|
||
vcPollTimer = null;
|
||
}
|
||
|
||
async function vcPollCalls() {
|
||
try {
|
||
const url = vcCallId ? `/calls/poll?call_id=${vcCallId}` : '/calls/poll';
|
||
const r = await fetch(url, { headers: { 'Accept': 'application/json', 'X-CSRF-TOKEN': CP_CSRF } });
|
||
const d = await r.json();
|
||
|
||
if (d.type === 'incoming' && !vcCallId) {
|
||
vcShowIncoming(d.caller.name, d.caller.avatar, d.call_id);
|
||
} else if (d.type === 'status') {
|
||
if (d.status === 'active' && document.getElementById('call-overlay')?.classList.contains('show')) {
|
||
// Other side answered our outgoing — switch to active bar
|
||
const nameEl = document.getElementById('call-name-el');
|
||
vcShowActive(nameEl?.textContent);
|
||
} else if (d.status === 'ended' || d.status === 'declined') {
|
||
vcCallId = null;
|
||
vcHideOverlay();
|
||
vcHideCallBar();
|
||
vcLeaveAgora();
|
||
vcStopCallPoll();
|
||
if (d.status === 'declined') showToast('Arama reddedildi.', 'info');
|
||
else showToast('Arama sona erdi.', 'info');
|
||
}
|
||
}
|
||
} catch(_) {}
|
||
}
|
||
|
||
// Start polling for calls immediately (even without active call)
|
||
vcStartCallPoll();
|
||
|
||
/* ════════════════════════════════════════════════════
|
||
UTIL
|
||
════════════════════════════════════════════════════ */
|
||
function escH(s) {
|
||
return String(s || '').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||
}
|
||
|
||
})();
|
||
</script>
|
||
@endauth
|
||
|
||
{{-- Crisp Chat --}}
|
||
<script type="text/javascript">
|
||
window.$crisp=[];
|
||
window.$crisp.push(["config","position:reverse",[true]]);
|
||
window.CRISP_WEBSITE_ID="a484d897-f0e5-478c-acc5-ac9ec0814dd8";
|
||
(function(){d=document;s=d.createElement("script");s.src="https://client.crisp.chat/l.js";s.async=1;d.getElementsByTagName("head")[0].appendChild(s);})();
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|