2019 lines
74 KiB
PHP
2019 lines
74 KiB
PHP
@extends('frontend.layouts.app')
|
||
@section('title', 'Keşfet — Sana Uygun Animeyi Bul')
|
||
@section('meta_description', 'Kaydır, beğen, listene ekle. Binlerce anime arasından sana uygun olanı saniyeler içinde bul.')
|
||
|
||
@push('styles')
|
||
<style>
|
||
/* ── Page shell — hide footer/mobile-nav on this page ─── */
|
||
footer,
|
||
.mob-nav,
|
||
#mobile-nav,
|
||
#mob-bottom-nav,
|
||
[class*="bottom-nav"] { display: none !important; }
|
||
|
||
/* ════════════════════════════════════════════════════════
|
||
DISCOVER PAGE
|
||
════════════════════════════════════════════════════════ */
|
||
.dsc-page {
|
||
min-height: 100vh;
|
||
display: grid;
|
||
grid-template-rows: auto auto auto 1fr auto;
|
||
align-items: start;
|
||
background: var(--bg);
|
||
position: relative;
|
||
overflow: hidden;
|
||
padding-top: var(--nav-h);
|
||
padding-bottom: 110px;
|
||
}
|
||
|
||
/* Ambient glow orbs */
|
||
.dsc-orb {
|
||
position: fixed;
|
||
border-radius: 50%;
|
||
pointer-events: none;
|
||
z-index: 0;
|
||
filter: blur(80px);
|
||
}
|
||
.dsc-orb-1 {
|
||
width: 500px; height: 500px;
|
||
top: -160px; left: -160px;
|
||
background: radial-gradient(circle, rgba(0,245,255,.055), transparent 65%);
|
||
animation: orbDrift1 12s ease-in-out infinite alternate;
|
||
}
|
||
.dsc-orb-2 {
|
||
width: 420px; height: 420px;
|
||
bottom: 60px; right: -120px;
|
||
background: radial-gradient(circle, rgba(255,45,125,.05), transparent 65%);
|
||
animation: orbDrift2 14s ease-in-out infinite alternate;
|
||
}
|
||
@keyframes orbDrift1 { to { transform: translate(40px, 30px); } }
|
||
@keyframes orbDrift2 { to { transform: translate(-30px, -20px); } }
|
||
|
||
/* ── Header ─────────────────────────────────────────── */
|
||
.dsc-header {
|
||
position: relative;
|
||
z-index: 10;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
padding: 20px 20px 0;
|
||
max-width: 480px;
|
||
width: 100%;
|
||
margin: 0 auto;
|
||
}
|
||
.dsc-back {
|
||
width: 40px; height: 40px;
|
||
border-radius: 50%;
|
||
background: rgba(255,255,255,.04);
|
||
border: 1px solid rgba(255,255,255,.08);
|
||
display: flex; align-items: center; justify-content: center;
|
||
color: var(--text3);
|
||
text-decoration: none;
|
||
flex-shrink: 0;
|
||
transition: all .2s;
|
||
}
|
||
.dsc-back:hover { background: rgba(0,245,255,.08); border-color: rgba(0,245,255,.3); color: var(--accent2); }
|
||
.dsc-heading { flex: 1 }
|
||
.dsc-heading-main {
|
||
display: block;
|
||
font-family: var(--font-display);
|
||
font-size: .82rem;
|
||
font-weight: 700;
|
||
letter-spacing: .12em;
|
||
text-transform: uppercase;
|
||
background: linear-gradient(90deg, var(--accent2) 0%, var(--accent3) 100%);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
}
|
||
.dsc-heading-sub { font-size: .62rem; color: var(--text3); display: block; margin-top: 1px; }
|
||
.dsc-filter-toggle {
|
||
width: 40px; height: 40px;
|
||
border-radius: 50%;
|
||
background: rgba(255,255,255,.04);
|
||
border: 1px solid rgba(255,255,255,.08);
|
||
color: var(--text3);
|
||
display: flex; align-items: center; justify-content: center;
|
||
cursor: pointer;
|
||
transition: all .2s;
|
||
position: relative;
|
||
font-size: .9rem;
|
||
}
|
||
.dsc-filter-toggle:hover,
|
||
.dsc-filter-toggle.active { border-color: rgba(0,245,255,.3); color: var(--accent2); background: rgba(0,245,255,.06); }
|
||
.dsc-filter-dot {
|
||
position: absolute; top: 8px; right: 8px;
|
||
width: 7px; height: 7px; border-radius: 50%;
|
||
background: var(--accent); display: none;
|
||
}
|
||
.dsc-filter-dot.on { display: block; }
|
||
|
||
/* ── Filter panel ───────────────────────────────────── */
|
||
.dsc-filters {
|
||
position: relative; z-index: 9;
|
||
max-width: 480px; width: 100%;
|
||
margin: 0 auto;
|
||
overflow: hidden;
|
||
max-height: 0;
|
||
transition: max-height .35s cubic-bezier(.4,0,.2,1);
|
||
padding: 0 20px;
|
||
}
|
||
.dsc-filters.open { max-height: 240px; padding: 14px 20px 2px; }
|
||
.dsc-fgroup { margin-bottom: 12px; }
|
||
.dsc-fgroup label {
|
||
display: block; font-size: .58rem; text-transform: uppercase;
|
||
letter-spacing: .14em; color: var(--text3); margin-bottom: 7px; font-weight: 700;
|
||
}
|
||
.dsc-fpills { display: flex; gap: 6px; flex-wrap: wrap; }
|
||
.dfp {
|
||
padding: 5px 13px; border-radius: 999px; font-size: .67rem;
|
||
background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.07);
|
||
color: var(--text3); cursor: pointer; transition: all .15s;
|
||
white-space: nowrap; font-family: var(--font);
|
||
}
|
||
.dfp:hover { border-color: rgba(0,245,255,.3); color: var(--text2); }
|
||
.dfp.active { background: rgba(0,245,255,.1); border-color: var(--accent2); color: var(--accent2); }
|
||
|
||
/* ── Progress bar ───────────────────────────────────── */
|
||
.dsc-progress {
|
||
position: relative; z-index: 9;
|
||
max-width: 480px; width: 100%;
|
||
margin: 12px auto 0;
|
||
padding: 0 20px;
|
||
display: flex; align-items: center; gap: 10px;
|
||
}
|
||
.dsc-progress-bar {
|
||
flex: 1; height: 2px; border-radius: 999px;
|
||
background: rgba(255,255,255,.06); overflow: hidden;
|
||
}
|
||
.dsc-progress-fill {
|
||
height: 100%;
|
||
background: linear-gradient(90deg, var(--accent2), var(--accent3));
|
||
border-radius: 999px;
|
||
transition: width .45s cubic-bezier(.4,0,.2,1);
|
||
width: 0%;
|
||
}
|
||
.dsc-count-txt { font-size: .6rem; color: var(--text3); white-space: nowrap; min-width: 48px; text-align: right; }
|
||
|
||
/* ── Card stack area ────────────────────────────────── */
|
||
.dsc-stage {
|
||
position: relative; z-index: 5;
|
||
display: flex; align-items: center; justify-content: center;
|
||
padding: 16px 20px 0;
|
||
width: 100%;
|
||
}
|
||
.dsc-stack {
|
||
position: relative;
|
||
width: min(100%, 400px);
|
||
height: min(74vw, 520px);
|
||
}
|
||
|
||
/* ── Cards ──────────────────────────────────────────── */
|
||
.dsc-card {
|
||
position: absolute; inset: 0;
|
||
border-radius: 24px;
|
||
overflow: hidden;
|
||
box-shadow: 0 28px 70px rgba(0,0,0,.7), 0 0 0 1px rgba(255,255,255,.05);
|
||
cursor: grab;
|
||
user-select: none;
|
||
transform-origin: center 115%;
|
||
will-change: transform, opacity;
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
.dsc-card:active { cursor: grabbing; }
|
||
|
||
/* Entrance animation */
|
||
@keyframes cardEnter {
|
||
from { opacity: 0; transform: translateY(32px) scale(.94); }
|
||
to { opacity: 1; transform: translateY(0) scale(1); }
|
||
}
|
||
.dsc-card.entering { animation: cardEnter .42s cubic-bezier(.175,.885,.32,1.275) forwards; }
|
||
|
||
/* Stack positions */
|
||
.dsc-card.pos-0 { z-index: 10; transition: transform .32s cubic-bezier(.175,.885,.32,1.275); }
|
||
.dsc-card.pos-1 {
|
||
z-index: 9; pointer-events: none;
|
||
transform: scale(.95) translateY(18px);
|
||
transition: transform .32s cubic-bezier(.175,.885,.32,1.275);
|
||
}
|
||
.dsc-card.pos-2 {
|
||
z-index: 8; pointer-events: none;
|
||
transform: scale(.90) translateY(36px);
|
||
opacity: .55;
|
||
transition: transform .32s cubic-bezier(.175,.885,.32,1.275), opacity .32s;
|
||
}
|
||
|
||
/* Fly-out animations */
|
||
.dsc-card.going-right {
|
||
transition: transform .4s cubic-bezier(.55,.055,.675,.19), opacity .4s !important;
|
||
transform: translateX(160%) rotate(28deg) !important;
|
||
opacity: 0 !important; pointer-events: none;
|
||
}
|
||
.dsc-card.going-left {
|
||
transition: transform .4s cubic-bezier(.55,.055,.675,.19), opacity .4s !important;
|
||
transform: translateX(-160%) rotate(-28deg) !important;
|
||
opacity: 0 !important; pointer-events: none;
|
||
}
|
||
|
||
/* Card image */
|
||
.dsc-card-img { position: absolute; inset: 0; }
|
||
.dsc-card-img img {
|
||
width: 100%; height: 100%; object-fit: cover;
|
||
display: block; pointer-events: none; user-select: none; -webkit-user-drag: none;
|
||
}
|
||
.dsc-card-gradient {
|
||
position: absolute; inset: 0;
|
||
background: linear-gradient(
|
||
180deg,
|
||
rgba(6,6,13,.12) 0%,
|
||
rgba(6,6,13,0) 30%,
|
||
rgba(6,6,13,.42) 60%,
|
||
rgba(6,6,13,.9) 80%,
|
||
rgba(6,6,13,.98) 100%
|
||
);
|
||
}
|
||
|
||
/* Color tint overlay during drag */
|
||
.dsc-card-tint {
|
||
position: absolute; inset: 0; pointer-events: none; opacity: 0;
|
||
transition: opacity .08s;
|
||
z-index: 4;
|
||
}
|
||
.dsc-card.hint-like .dsc-card-tint { background: rgba(0,245,255,.08); opacity: 1; }
|
||
.dsc-card.hint-skip .dsc-card-tint { background: rgba(255,45,125,.08); opacity: 1; }
|
||
|
||
/* Swipe stamps */
|
||
.dsc-stamp {
|
||
position: absolute; top: 24px; z-index: 6;
|
||
padding: 6px 16px; border-radius: 10px;
|
||
font-size: .74rem; font-weight: 800;
|
||
letter-spacing: .1em; text-transform: uppercase;
|
||
opacity: 0; transition: opacity .1s; pointer-events: none;
|
||
backdrop-filter: blur(8px);
|
||
}
|
||
.dsc-stamp-like { right: 20px; border: 2.5px solid #00f5ff; color: #00f5ff; background: rgba(0,245,255,.12); transform: rotate(7deg); }
|
||
.dsc-stamp-skip { left: 20px; border: 2.5px solid #ff2d7d; color: #ff2d7d; background: rgba(255,45,125,.1); transform: rotate(-7deg); }
|
||
.dsc-card.hint-like .dsc-stamp-like { opacity: 1; }
|
||
.dsc-card.hint-skip .dsc-stamp-skip { opacity: 1; }
|
||
|
||
/* No-image fallback */
|
||
.dsc-card-noimg {
|
||
position: absolute; inset: 0;
|
||
background: linear-gradient(145deg, var(--surface2), #0e0e1c);
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 4rem; color: rgba(255,255,255,.08);
|
||
}
|
||
|
||
/* Card info layer */
|
||
.dsc-card-info {
|
||
position: absolute; bottom: 0; left: 0; right: 0;
|
||
padding: 20px 18px 18px;
|
||
z-index: 5;
|
||
}
|
||
.dsc-card-genres { display: flex; gap: 5px; flex-wrap: wrap; margin-bottom: 9px; }
|
||
.dsc-genre-pill {
|
||
font-size: .58rem; padding: 3px 10px; border-radius: 999px;
|
||
background: rgba(0,245,255,.1); border: 1px solid rgba(0,245,255,.2);
|
||
color: var(--accent2); font-weight: 600; letter-spacing: .04em;
|
||
}
|
||
.dsc-card-title {
|
||
font-size: clamp(1.2rem, 5.5vw, 1.55rem);
|
||
font-weight: 800; color: #fff; line-height: 1.15;
|
||
margin: 0 0 7px;
|
||
text-shadow: 0 2px 14px rgba(0,0,0,.5);
|
||
}
|
||
.dsc-card-meta {
|
||
display: flex; align-items: center; gap: 8px;
|
||
font-size: .68rem; color: rgba(240,244,255,.5);
|
||
flex-wrap: wrap; margin-bottom: 8px;
|
||
}
|
||
.dsc-card-star {
|
||
display: flex; align-items: center; gap: 3px;
|
||
color: #fbbf24; font-weight: 700;
|
||
}
|
||
.dsc-card-star svg { width: 10px; height: 10px; fill: #fbbf24; }
|
||
.dsc-card-hook {
|
||
font-size: .75rem; color: rgba(240,244,255,.65); font-style: italic;
|
||
line-height: 1.55; margin: 0;
|
||
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
|
||
}
|
||
|
||
/* Tap-hint pill (shows briefly on first load) */
|
||
.dsc-hint-pill {
|
||
position: absolute; bottom: 20px; left: 50%; z-index: 6;
|
||
transform: translateX(-50%);
|
||
background: rgba(255,255,255,.08); backdrop-filter: blur(10px);
|
||
border: 1px solid rgba(255,255,255,.1); border-radius: 999px;
|
||
font-size: .62rem; color: rgba(255,255,255,.5);
|
||
padding: 5px 14px; white-space: nowrap; pointer-events: none;
|
||
animation: hintFadeOut 3s ease forwards 2.5s;
|
||
}
|
||
@keyframes hintFadeOut { to { opacity: 0; } }
|
||
|
||
/* ── Action bar ─────────────────────────────────────── */
|
||
.dsc-actions {
|
||
position: fixed; bottom: 0; left: 0; right: 0;
|
||
display: flex; align-items: center; justify-content: center;
|
||
gap: 16px;
|
||
padding: 16px 0 calc(22px + env(safe-area-inset-bottom, 0px));
|
||
background: linear-gradient(to top, rgba(6,6,13,1) 55%, transparent);
|
||
z-index: 50; pointer-events: none;
|
||
}
|
||
.dsc-actions > * { pointer-events: auto; }
|
||
|
||
.dsc-btn {
|
||
display: flex; align-items: center; justify-content: center;
|
||
border: none; border-radius: 50%; cursor: pointer;
|
||
transition: transform .15s cubic-bezier(.175,.885,.32,1.275), box-shadow .2s;
|
||
flex-shrink: 0; -webkit-tap-highlight-color: transparent; outline: none;
|
||
}
|
||
.dsc-btn:active { transform: scale(.85) !important; }
|
||
.dsc-btn svg, .dsc-btn i { pointer-events: none; flex-shrink: 0; }
|
||
.dsc-btn:disabled { opacity: .3; cursor: default; pointer-events: none; }
|
||
|
||
.dsc-btn-skip {
|
||
width: 56px; height: 56px;
|
||
background: rgba(255,45,125,.08);
|
||
border: 1.5px solid rgba(255,45,125,.3);
|
||
color: #ff2d7d;
|
||
}
|
||
.dsc-btn-skip:hover:not(:disabled) {
|
||
border-color: #ff2d7d;
|
||
box-shadow: 0 0 28px rgba(255,45,125,.25), 0 4px 12px rgba(0,0,0,.3);
|
||
transform: scale(1.09);
|
||
}
|
||
|
||
.dsc-btn-info {
|
||
width: 44px; height: 44px;
|
||
background: rgba(255,255,255,.05);
|
||
border: 1.5px solid rgba(255,255,255,.1);
|
||
color: var(--text3); font-size: 1rem;
|
||
}
|
||
.dsc-btn-info:hover:not(:disabled) {
|
||
border-color: rgba(184,77,255,.4); color: var(--accent3);
|
||
transform: scale(1.09);
|
||
}
|
||
|
||
.dsc-btn-like {
|
||
width: 70px; height: 70px;
|
||
background: linear-gradient(145deg, rgba(0,245,255,.14), rgba(0,245,255,.05));
|
||
border: 1.5px solid rgba(0,245,255,.4);
|
||
color: var(--accent2);
|
||
box-shadow: 0 0 30px rgba(0,245,255,.12), 0 4px 16px rgba(0,0,0,.3);
|
||
}
|
||
.dsc-btn-like:hover:not(:disabled) {
|
||
border-color: var(--accent2);
|
||
box-shadow: 0 0 50px rgba(0,245,255,.3), 0 4px 16px rgba(0,0,0,.3);
|
||
transform: scale(1.1);
|
||
}
|
||
@keyframes likePulse {
|
||
0% { transform: scale(1); }
|
||
35% { transform: scale(1.24); }
|
||
100% { transform: scale(1); }
|
||
}
|
||
.dsc-btn-like.pulse { animation: likePulse .3s ease; }
|
||
|
||
/* ── Keyboard hint ──────────────────────────────────── */
|
||
.dsc-kbd {
|
||
position: fixed; bottom: 118px; left: 50%; transform: translateX(-50%);
|
||
display: flex; gap: 20px; font-size: .6rem; color: var(--text3);
|
||
pointer-events: none; z-index: 50; white-space: nowrap;
|
||
}
|
||
.dsc-kbd kbd {
|
||
background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.1);
|
||
border-radius: 5px; padding: 2px 7px; font-family: var(--font);
|
||
font-size: .58rem; margin-right: 4px; color: var(--text2);
|
||
}
|
||
@media (max-width: 768px) { .dsc-kbd { display: none; } }
|
||
|
||
/* ── Loading / Empty states ─────────────────────────── */
|
||
.dsc-state {
|
||
position: absolute; inset: 0;
|
||
display: flex; flex-direction: column;
|
||
align-items: center; justify-content: center;
|
||
text-align: center; padding: 24px; z-index: 20;
|
||
border-radius: 24px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* ── Splash loader ──────────────────────────────────── */
|
||
.dsc-splash {
|
||
position: absolute; inset: 0;
|
||
background: linear-gradient(160deg, #0a0a18 0%, #0d0d22 50%, #080814 100%);
|
||
border-radius: 24px;
|
||
display: flex; flex-direction: column;
|
||
align-items: center; justify-content: center;
|
||
gap: 0; z-index: 21; overflow: hidden;
|
||
padding: 28px 24px;
|
||
}
|
||
|
||
/* Floating icons container */
|
||
.splash-floats {
|
||
position: absolute; inset: 0; pointer-events: none; overflow: hidden;
|
||
}
|
||
.sf-icon {
|
||
position: absolute; bottom: -40px;
|
||
font-size: 1.4rem; opacity: 0;
|
||
animation: sfFloat linear infinite;
|
||
filter: drop-shadow(0 0 8px currentColor);
|
||
}
|
||
@keyframes sfFloat {
|
||
0% { opacity: 0; transform: translateY(0) rotate(0deg) scale(.7); }
|
||
10% { opacity: .9; }
|
||
85% { opacity: .6; }
|
||
100% { opacity: 0; transform: translateY(-120%) rotate(25deg) scale(1.1); }
|
||
}
|
||
|
||
/* Logo mark */
|
||
.splash-logo {
|
||
font-family: var(--font-display);
|
||
font-size: .7rem; font-weight: 700;
|
||
letter-spacing: .22em; text-transform: uppercase;
|
||
background: linear-gradient(90deg, var(--accent2), var(--accent3));
|
||
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
margin-bottom: 20px; opacity: .7;
|
||
}
|
||
|
||
/* Pulsing ring */
|
||
.splash-ring-wrap {
|
||
position: relative; width: 76px; height: 76px;
|
||
display: flex; align-items: center; justify-content: center;
|
||
margin-bottom: 28px; flex-shrink: 0;
|
||
}
|
||
.splash-ring {
|
||
position: absolute; inset: 0; border-radius: 50%;
|
||
border: 2px solid transparent;
|
||
border-top-color: var(--accent2);
|
||
border-right-color: rgba(0,245,255,.3);
|
||
animation: splashSpin 1.1s linear infinite;
|
||
}
|
||
.splash-ring-2 {
|
||
position: absolute; inset: 8px; border-radius: 50%;
|
||
border: 1.5px solid transparent;
|
||
border-bottom-color: var(--accent3);
|
||
border-left-color: rgba(184,77,255,.3);
|
||
animation: splashSpin 1.7s linear infinite reverse;
|
||
}
|
||
.splash-icon-center {
|
||
font-size: 1.6rem;
|
||
animation: splashIconPulse 1.8s ease-in-out infinite;
|
||
filter: drop-shadow(0 0 12px rgba(0,245,255,.5));
|
||
}
|
||
@keyframes splashSpin { to { transform: rotate(360deg); } }
|
||
@keyframes splashIconPulse {
|
||
0%,100% { transform: scale(1); opacity: .8; }
|
||
50% { transform: scale(1.15); opacity: 1; }
|
||
}
|
||
|
||
/* Cycling text */
|
||
.splash-text-wrap {
|
||
height: 28px; overflow: hidden; position: relative;
|
||
width: 100%; display: flex; align-items: center; justify-content: center;
|
||
}
|
||
.splash-msg {
|
||
position: absolute; font-size: .82rem; font-weight: 600;
|
||
color: var(--text2); letter-spacing: .02em;
|
||
opacity: 0; transform: translateY(16px);
|
||
transition: opacity .4s ease, transform .4s ease;
|
||
white-space: nowrap;
|
||
}
|
||
.splash-msg.active {
|
||
opacity: 1; transform: translateY(0);
|
||
}
|
||
.splash-msg.exit {
|
||
opacity: 0; transform: translateY(-16px);
|
||
}
|
||
|
||
/* Sub text */
|
||
.splash-sub {
|
||
margin-top: 10px; font-size: .65rem; color: var(--text3);
|
||
animation: splashSubPulse 2s ease-in-out infinite;
|
||
}
|
||
@keyframes splashSubPulse {
|
||
0%,100% { opacity: .4; }
|
||
50% { opacity: .8; }
|
||
}
|
||
|
||
/* Dot bar */
|
||
.splash-dots {
|
||
display: flex; gap: 5px; margin-top: 18px;
|
||
}
|
||
.splash-dot {
|
||
width: 5px; height: 5px; border-radius: 50%;
|
||
background: rgba(0,245,255,.25);
|
||
animation: splashDotPop .8s ease-in-out infinite;
|
||
}
|
||
.splash-dot:nth-child(2) { animation-delay: .15s; }
|
||
.splash-dot:nth-child(3) { animation-delay: .3s; }
|
||
@keyframes splashDotPop {
|
||
0%,100% { transform: scale(1); background: rgba(0,245,255,.25); }
|
||
50% { transform: scale(1.5); background: rgba(0,245,255,.8); }
|
||
}
|
||
|
||
@keyframes spin { to { transform: rotate(360deg); } }
|
||
|
||
/* ── Results screen (full-page overlay over stack) ───── */
|
||
.dsc-results-overlay {
|
||
position: fixed; inset: 0; z-index: 80;
|
||
background: var(--bg);
|
||
overflow-y: auto; overflow-x: hidden;
|
||
-webkit-overflow-scrolling: touch;
|
||
padding-top: var(--nav-h);
|
||
padding-bottom: 120px;
|
||
animation: resultsFadeIn .5s cubic-bezier(.22,1,.36,1);
|
||
}
|
||
@keyframes resultsFadeIn {
|
||
from { opacity: 0; transform: translateY(24px); }
|
||
to { opacity: 1; transform: none; }
|
||
}
|
||
.res-wrap { max-width: 480px; margin: 0 auto; padding: 0 18px; }
|
||
|
||
/* Trophy header */
|
||
.res-header {
|
||
text-align: center; padding: 28px 0 22px;
|
||
position: relative;
|
||
}
|
||
.res-trophy {
|
||
font-size: 3.2rem; display: block; margin-bottom: 12px;
|
||
animation: trophyBounce .7s cubic-bezier(.175,.885,.32,1.275) .2s both;
|
||
filter: drop-shadow(0 0 20px rgba(0,245,255,.4));
|
||
}
|
||
@keyframes trophyBounce {
|
||
from { opacity: 0; transform: scale(0) rotate(-15deg); }
|
||
to { opacity: 1; transform: scale(1) rotate(0deg); }
|
||
}
|
||
.res-title {
|
||
font-family: var(--font-display); font-size: 1.3rem; font-weight: 900;
|
||
background: linear-gradient(90deg, var(--accent2), var(--accent3));
|
||
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
||
background-clip: text; letter-spacing: .05em; margin-bottom: 6px;
|
||
}
|
||
.res-subtitle { font-size: .76rem; color: var(--text3); }
|
||
|
||
/* Stats row */
|
||
.res-stats {
|
||
display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 22px;
|
||
}
|
||
.res-stat {
|
||
background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.06);
|
||
border-radius: 14px; padding: 14px 16px; text-align: center;
|
||
}
|
||
.res-stat-val { font-size: 1.6rem; font-weight: 800; display: block; line-height: 1; }
|
||
.res-stat-val.like { color: var(--accent2); text-shadow: 0 0 18px rgba(0,245,255,.3); }
|
||
.res-stat-val.skip { color: #ff2d7d; text-shadow: 0 0 18px rgba(255,45,125,.3); }
|
||
.res-stat-label { font-size: .6rem; color: var(--text3); text-transform: uppercase; letter-spacing: .1em; margin-top: 5px; display: block; }
|
||
|
||
/* Section titles */
|
||
.res-sec { margin-bottom: 20px; }
|
||
.res-sec-title {
|
||
font-size: .62rem; font-weight: 800; text-transform: uppercase;
|
||
letter-spacing: .16em; color: var(--text3); margin-bottom: 12px;
|
||
display: flex; align-items: center; gap: 8px;
|
||
}
|
||
.res-sec-title::before {
|
||
content: ''; display: block; width: 16px; height: 2px; border-radius: 1px; flex-shrink: 0;
|
||
}
|
||
.res-sec-title.cyan::before { background: var(--accent2); }
|
||
.res-sec-title.purple::before{ background: var(--accent3); }
|
||
.res-sec-title.pink::before { background: var(--accent); }
|
||
|
||
/* Liked anime strip */
|
||
.res-liked-strip {
|
||
display: flex; gap: 9px; overflow-x: auto; padding-bottom: 6px;
|
||
}
|
||
.res-liked-strip::-webkit-scrollbar { display: none; }
|
||
.res-liked-card {
|
||
flex-shrink: 0; width: 72px; text-decoration: none;
|
||
}
|
||
.res-liked-poster {
|
||
width: 72px; height: 100px; border-radius: 10px; overflow: hidden;
|
||
position: relative; border: 1.5px solid rgba(0,245,255,.2);
|
||
box-shadow: 0 4px 16px rgba(0,0,0,.4);
|
||
}
|
||
.res-liked-poster img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
||
.res-liked-poster-ph {
|
||
width: 100%; height: 100%; background: var(--surface2);
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 1.5rem; color: var(--text3);
|
||
}
|
||
.res-liked-heart {
|
||
position: absolute; bottom: 4px; right: 4px;
|
||
width: 18px; height: 18px; border-radius: 50%;
|
||
background: rgba(0,245,255,.2); backdrop-filter: blur(4px);
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: .5rem; color: var(--accent2);
|
||
}
|
||
.res-liked-name {
|
||
font-size: .55rem; color: var(--text3); text-align: center;
|
||
margin-top: 5px; line-height: 1.3;
|
||
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
|
||
}
|
||
|
||
/* AI rec cards */
|
||
.res-recs { display: flex; flex-direction: column; gap: 10px; }
|
||
.res-rec-card {
|
||
display: flex; gap: 12px; align-items: flex-start;
|
||
background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.06);
|
||
border-radius: 14px; padding: 12px; text-decoration: none;
|
||
transition: background .2s, border-color .2s;
|
||
}
|
||
.res-rec-card:hover {
|
||
background: rgba(184,77,255,.06); border-color: rgba(184,77,255,.2);
|
||
}
|
||
.res-rec-cover {
|
||
width: 50px; height: 70px; border-radius: 8px; overflow: hidden; flex-shrink: 0;
|
||
border: 1px solid rgba(255,255,255,.07);
|
||
}
|
||
.res-rec-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
||
.res-rec-cover-ph {
|
||
width: 100%; height: 100%; background: var(--surface2);
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 1.2rem; color: var(--text3);
|
||
}
|
||
.res-rec-body { flex: 1; min-width: 0; }
|
||
.res-rec-title { font-size: .82rem; font-weight: 700; color: var(--text); margin-bottom: 4px; line-height: 1.3; }
|
||
.res-rec-meta {
|
||
display: flex; gap: 7px; font-size: .62rem; color: var(--text3); margin-bottom: 6px; flex-wrap: wrap;
|
||
}
|
||
.res-rec-meta .star { color: #fbbf24; }
|
||
.res-rec-reason {
|
||
font-size: .72rem; color: rgba(184,77,255,.8); font-style: italic;
|
||
line-height: 1.5;
|
||
}
|
||
.res-rec-reason::before { content: '"'; }
|
||
.res-rec-reason::after { content: '"'; }
|
||
.res-rec-genres { display: flex; gap: 4px; flex-wrap: wrap; }
|
||
.res-rec-genre {
|
||
font-size: .56rem; padding: 2px 7px; border-radius: 999px;
|
||
background: rgba(184,77,255,.08); border: 1px solid rgba(184,77,255,.18);
|
||
color: var(--accent3);
|
||
}
|
||
|
||
/* Where to find box */
|
||
.res-find-box {
|
||
background: linear-gradient(125deg, rgba(0,245,255,.05), rgba(184,77,255,.04));
|
||
border: 1px solid rgba(0,245,255,.14); border-radius: 16px;
|
||
padding: 18px; margin-bottom: 20px;
|
||
}
|
||
.res-find-title {
|
||
font-size: .7rem; font-weight: 800; color: var(--accent2);
|
||
text-transform: uppercase; letter-spacing: .1em; margin-bottom: 14px;
|
||
display: flex; align-items: center; gap: 7px;
|
||
}
|
||
.res-find-steps { display: flex; flex-direction: column; gap: 10px; }
|
||
.res-find-step {
|
||
display: flex; align-items: flex-start; gap: 10px;
|
||
}
|
||
.res-find-num {
|
||
width: 22px; height: 22px; border-radius: 50%; flex-shrink: 0;
|
||
background: rgba(0,245,255,.1); border: 1px solid rgba(0,245,255,.2);
|
||
color: var(--accent2); font-size: .6rem; font-weight: 800;
|
||
display: flex; align-items: center; justify-content: center; margin-top: 1px;
|
||
}
|
||
.res-find-text { font-size: .76rem; color: var(--text2); line-height: 1.5; }
|
||
.res-find-text strong { color: var(--text); font-weight: 700; }
|
||
.res-find-text a { color: var(--accent2); text-decoration: none; font-weight: 600; }
|
||
.res-find-text a:hover { text-decoration: underline; }
|
||
|
||
/* Action buttons */
|
||
.res-actions { display: flex; flex-direction: column; gap: 8px; margin-bottom: 10px; }
|
||
.res-btn-continue {
|
||
width: 100%; padding: 15px; border-radius: 14px;
|
||
background: linear-gradient(135deg, rgba(0,245,255,.18), rgba(0,245,255,.08));
|
||
border: 1.5px solid rgba(0,245,255,.4); color: var(--accent2);
|
||
font-size: .9rem; font-weight: 800; cursor: pointer;
|
||
display: flex; align-items: center; justify-content: center; gap: 9px;
|
||
font-family: var(--font); transition: all .2s;
|
||
box-shadow: 0 0 28px rgba(0,245,255,.1);
|
||
}
|
||
.res-btn-continue:hover { box-shadow: 0 0 48px rgba(0,245,255,.25); border-color: var(--accent2); }
|
||
.res-btn-profile {
|
||
width: 100%; padding: 13px; border-radius: 14px;
|
||
background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.08);
|
||
color: var(--text2); font-size: .82rem; font-weight: 600; cursor: pointer;
|
||
display: flex; align-items: center; justify-content: center; gap: 8px;
|
||
font-family: var(--font); text-decoration: none; transition: all .2s;
|
||
}
|
||
.res-btn-profile:hover { border-color: rgba(184,77,255,.3); color: var(--accent3); }
|
||
|
||
/* Guest notice */
|
||
.res-guest-notice {
|
||
background: rgba(251,191,36,.07); border: 1px solid rgba(251,191,36,.2);
|
||
border-radius: 12px; padding: 12px 14px; margin-bottom: 16px;
|
||
font-size: .74rem; color: rgba(251,191,36,.8); line-height: 1.5; text-align: center;
|
||
}
|
||
.res-guest-notice a { color: #fbbf24; font-weight: 700; text-decoration: none; }
|
||
|
||
.dsc-restart {
|
||
display: inline-flex; align-items: center; gap: 7px;
|
||
padding: 11px 24px; border-radius: 999px;
|
||
border: 1px solid var(--accent2); background: rgba(0,245,255,.08);
|
||
color: var(--accent2); font-size: .8rem; font-weight: 600; cursor: pointer;
|
||
transition: all .2s;
|
||
}
|
||
.dsc-restart:hover { background: rgba(0,245,255,.15); box-shadow: 0 0 24px rgba(0,245,255,.2); }
|
||
|
||
/* ════════════════════════════════════════════════════════
|
||
BOTTOM SHEET
|
||
════════════════════════════════════════════════════════ */
|
||
.bs-overlay {
|
||
position: fixed; inset: 0; z-index: 200;
|
||
background: rgba(0,0,0,0);
|
||
backdrop-filter: blur(0px);
|
||
pointer-events: none;
|
||
transition: background .35s, backdrop-filter .35s;
|
||
}
|
||
.bs-overlay.open {
|
||
background: rgba(0,0,0,.65);
|
||
backdrop-filter: blur(14px);
|
||
pointer-events: auto;
|
||
}
|
||
|
||
.bs-sheet {
|
||
position: fixed; left: 0; right: 0; bottom: 0; z-index: 201;
|
||
max-width: 520px; margin: 0 auto;
|
||
background: #0d0d1a;
|
||
border: 1px solid rgba(255,255,255,.07);
|
||
border-bottom: none;
|
||
border-radius: 26px 26px 0 0;
|
||
transform: translateY(100%);
|
||
transition: transform .45s cubic-bezier(.32,.72,0,1);
|
||
overflow: hidden;
|
||
display: flex; flex-direction: column;
|
||
max-height: 92vh;
|
||
box-shadow: 0 -20px 60px rgba(0,0,0,.6);
|
||
}
|
||
.bs-sheet.open { transform: translateY(0); }
|
||
|
||
/* Handle */
|
||
.bs-handle-row {
|
||
display: flex; align-items: center; justify-content: center;
|
||
padding: 12px 0 6px; flex-shrink: 0;
|
||
}
|
||
.bs-handle {
|
||
width: 40px; height: 4px; border-radius: 2px;
|
||
background: rgba(255,255,255,.14); cursor: grab;
|
||
}
|
||
.bs-handle:active { cursor: grabbing; }
|
||
|
||
/* Scrollable body */
|
||
.bs-body {
|
||
flex: 1; overflow-y: auto; overflow-x: hidden;
|
||
-webkit-overflow-scrolling: touch;
|
||
overscroll-behavior: contain;
|
||
}
|
||
.bs-body::-webkit-scrollbar { display: none; }
|
||
|
||
/* Banner image */
|
||
.bs-banner {
|
||
position: relative; width: 100%; aspect-ratio: 16/9; flex-shrink: 0;
|
||
}
|
||
.bs-banner img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
||
.bs-banner-grad {
|
||
position: absolute; inset: 0;
|
||
background: linear-gradient(180deg, transparent 50%, #0d0d1a 100%);
|
||
}
|
||
.bs-banner-ph {
|
||
width: 100%; aspect-ratio: 16/9;
|
||
background: linear-gradient(135deg, #14142a, #1a1a30);
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 3.5rem; color: rgba(255,255,255,.06);
|
||
}
|
||
|
||
/* Content */
|
||
.bs-content { padding: 4px 22px 20px; }
|
||
.bs-genres { display: flex; gap: 5px; flex-wrap: wrap; margin-bottom: 12px; }
|
||
.bs-genre-pill {
|
||
font-size: .6rem; padding: 3px 10px; border-radius: 999px;
|
||
background: rgba(0,245,255,.09); border: 1px solid rgba(0,245,255,.2);
|
||
color: var(--accent2); font-weight: 600;
|
||
}
|
||
.bs-title {
|
||
font-size: 1.35rem; font-weight: 800; color: #fff;
|
||
line-height: 1.15; margin: 0 0 10px;
|
||
}
|
||
.bs-meta {
|
||
display: flex; align-items: center; gap: 12px;
|
||
font-size: .72rem; color: rgba(240,244,255,.45);
|
||
flex-wrap: wrap; margin-bottom: 14px;
|
||
}
|
||
.bs-meta-star {
|
||
display: flex; align-items: center; gap: 4px;
|
||
color: #fbbf24; font-weight: 700;
|
||
}
|
||
.bs-meta-star svg { width: 11px; height: 11px; fill: #fbbf24; }
|
||
.bs-badges { display: flex; gap: 7px; flex-wrap: wrap; margin-bottom: 16px; }
|
||
.bs-badge {
|
||
font-size: .62rem; font-weight: 700; padding: 4px 12px; border-radius: 999px;
|
||
letter-spacing: .04em;
|
||
}
|
||
.bs-badge-type { background: rgba(184,77,255,.12); border: 1px solid rgba(184,77,255,.25); color: var(--accent3); }
|
||
.bs-badge-status { background: rgba(0,245,255,.09); border: 1px solid rgba(0,245,255,.2); color: var(--accent2); }
|
||
|
||
/* Stats grid */
|
||
.bs-stats {
|
||
display: grid; grid-template-columns: repeat(3,1fr);
|
||
gap: 1px; margin-bottom: 18px;
|
||
background: rgba(255,255,255,.06); border-radius: 14px; overflow: hidden;
|
||
border: 1px solid rgba(255,255,255,.06);
|
||
}
|
||
.bs-stat {
|
||
background: rgba(255,255,255,.025); padding: 12px 10px; text-align: center;
|
||
}
|
||
.bs-stat-val { font-size: .9rem; font-weight: 800; color: var(--text); display: block; }
|
||
.bs-stat-label { font-size: .58rem; color: var(--text3); text-transform: uppercase; letter-spacing: .1em; display: block; margin-top: 2px; }
|
||
|
||
/* Divider */
|
||
.bs-divider { height: 1px; background: rgba(255,255,255,.06); margin: 0 0 16px; }
|
||
|
||
/* Description */
|
||
.bs-desc-title { font-size: .6rem; text-transform: uppercase; letter-spacing: .12em; color: var(--text3); font-weight: 700; margin-bottom: 8px; }
|
||
.bs-desc { font-size: .82rem; color: var(--text2); line-height: 1.7; margin-bottom: 20px; }
|
||
|
||
/* Detail link */
|
||
.bs-detail-link {
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
padding: 13px 16px; border-radius: 13px;
|
||
background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.07);
|
||
color: var(--text2); text-decoration: none; font-size: .82rem; font-weight: 600;
|
||
transition: all .2s; margin-bottom: 14px;
|
||
}
|
||
.bs-detail-link:hover { border-color: rgba(184,77,255,.3); color: var(--accent3); }
|
||
|
||
/* Sheet action buttons */
|
||
.bs-actions { padding: 10px 22px calc(20px + env(safe-area-inset-bottom, 0px)); display: flex; gap: 10px; flex-shrink: 0; }
|
||
.bs-act-skip {
|
||
flex: 1; padding: 14px; border-radius: 14px;
|
||
background: rgba(255,45,125,.08); border: 1.5px solid rgba(255,45,125,.3);
|
||
color: #ff2d7d; font-size: .85rem; font-weight: 700;
|
||
cursor: pointer; transition: all .2s; display: flex; align-items: center; justify-content: center; gap: 7px;
|
||
}
|
||
.bs-act-skip:hover { background: rgba(255,45,125,.14); border-color: #ff2d7d; }
|
||
.bs-act-like {
|
||
flex: 2; padding: 14px; border-radius: 14px;
|
||
background: linear-gradient(135deg, rgba(0,245,255,.18), rgba(0,245,255,.08));
|
||
border: 1.5px solid rgba(0,245,255,.4); color: var(--accent2);
|
||
font-size: .85rem; font-weight: 700;
|
||
cursor: pointer; transition: all .2s; display: flex; align-items: center; justify-content: center; gap: 7px;
|
||
box-shadow: 0 0 24px rgba(0,245,255,.1);
|
||
}
|
||
.bs-act-like:hover { box-shadow: 0 0 40px rgba(0,245,255,.25); border-color: var(--accent2); }
|
||
|
||
/* ════════════════════════════════════════════════════════
|
||
MATCH / LIKE CELEBRATION OVERLAY
|
||
════════════════════════════════════════════════════════ */
|
||
.match-overlay {
|
||
position: fixed; inset: 0; z-index: 300;
|
||
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||
pointer-events: none; overflow: hidden;
|
||
}
|
||
.match-heart {
|
||
font-size: 5rem; line-height: 1;
|
||
filter: drop-shadow(0 0 30px rgba(0,245,255,.7));
|
||
animation: matchHeartPop .9s cubic-bezier(.175,.885,.32,1.275) forwards;
|
||
}
|
||
.match-text {
|
||
font-family: var(--font-display); font-size: 1.1rem; font-weight: 800;
|
||
color: var(--accent2); letter-spacing: .08em; text-transform: uppercase;
|
||
margin-top: 14px;
|
||
animation: matchTextFade .9s ease forwards;
|
||
text-shadow: 0 0 20px rgba(0,245,255,.5);
|
||
}
|
||
@keyframes matchHeartPop {
|
||
0% { opacity: 0; transform: scale(0) rotate(-20deg); }
|
||
55% { opacity: 1; transform: scale(1.35) rotate(8deg); }
|
||
75% { transform: scale(.95) rotate(-2deg); }
|
||
85% { opacity: 1; transform: scale(1.05) rotate(0deg); }
|
||
100% { opacity: 0; transform: scale(.9); }
|
||
}
|
||
@keyframes matchTextFade {
|
||
0%,20% { opacity: 0; transform: translateY(12px); }
|
||
45%,70%{ opacity: 1; transform: translateY(0); }
|
||
100% { opacity: 0; transform: translateY(-8px); }
|
||
}
|
||
|
||
/* Sparkle particles */
|
||
.sp-particle {
|
||
position: absolute;
|
||
width: 6px; height: 6px; border-radius: 50%;
|
||
animation: spFly 1s ease-out forwards;
|
||
pointer-events: none;
|
||
}
|
||
@keyframes spFly {
|
||
0% { opacity: 1; transform: translate(0,0) scale(1); }
|
||
100% { opacity: 0; transform: var(--fly); scale: 0; }
|
||
}
|
||
|
||
/* ════════════════════════════════════════════════════════
|
||
AÇIKLAMA PANELİ
|
||
════════════════════════════════════════════════════════ */
|
||
.dsc-desc-panel {
|
||
position: relative; z-index: 5;
|
||
max-width: 400px; width: calc(100% - 40px);
|
||
margin: 10px auto 0;
|
||
}
|
||
|
||
.dsc-desc-toggle {
|
||
width: 100%;
|
||
background: rgba(255,255,255,.04);
|
||
border: 1px solid rgba(255,255,255,.08);
|
||
border-radius: 14px;
|
||
padding: 11px 16px;
|
||
display: flex; align-items: center; gap: 10px;
|
||
cursor: pointer;
|
||
color: var(--text3);
|
||
font-family: var(--font); font-size: .76rem;
|
||
transition: background .2s, border-color .2s, color .2s;
|
||
text-align: left;
|
||
}
|
||
.dsc-desc-toggle:hover {
|
||
background: rgba(0,245,255,.06);
|
||
border-color: rgba(0,245,255,.2);
|
||
color: var(--text2);
|
||
}
|
||
.dsc-desc-toggle.open {
|
||
background: rgba(0,245,255,.07);
|
||
border-color: rgba(0,245,255,.22);
|
||
color: var(--accent2);
|
||
border-bottom-left-radius: 0;
|
||
border-bottom-right-radius: 0;
|
||
}
|
||
.dsc-desc-toggle-icon {
|
||
width: 26px; height: 26px; flex-shrink: 0;
|
||
border-radius: 50%;
|
||
background: rgba(0,245,255,.1);
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: .75rem; color: var(--accent2);
|
||
transition: transform .3s cubic-bezier(.4,0,.2,1);
|
||
}
|
||
.dsc-desc-toggle.open .dsc-desc-toggle-icon { transform: rotate(180deg); }
|
||
.dsc-desc-toggle-label { flex: 1; font-weight: 600; }
|
||
.dsc-desc-toggle-hint {
|
||
font-size: .62rem; color: var(--text3); font-style: italic;
|
||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||
max-width: 140px;
|
||
}
|
||
.dsc-desc-toggle.open .dsc-desc-toggle-hint { display: none; }
|
||
|
||
.dsc-desc-body {
|
||
max-height: 0; overflow: hidden;
|
||
background: rgba(0,245,255,.04);
|
||
border: 1px solid rgba(0,245,255,.22);
|
||
border-top: none;
|
||
border-bottom-left-radius: 14px;
|
||
border-bottom-right-radius: 14px;
|
||
transition: max-height .38s cubic-bezier(.4,0,.2,1);
|
||
}
|
||
.dsc-desc-body.open { max-height: 280px; }
|
||
|
||
.dsc-desc-inner {
|
||
padding: 14px 16px 16px;
|
||
}
|
||
.dsc-desc-anime-title {
|
||
font-size: .7rem; font-weight: 800; color: var(--accent2);
|
||
text-transform: uppercase; letter-spacing: .08em;
|
||
margin-bottom: 8px; display: flex; align-items: center; gap: 6px;
|
||
}
|
||
.dsc-desc-anime-title::before {
|
||
content: ''; display: block;
|
||
width: 14px; height: 2px; border-radius: 1px;
|
||
background: var(--accent2); flex-shrink: 0;
|
||
}
|
||
.dsc-desc-text {
|
||
font-size: .8rem; color: var(--text2); line-height: 1.7;
|
||
margin: 0 0 12px;
|
||
}
|
||
.dsc-desc-empty {
|
||
font-size: .76rem; color: var(--text3); font-style: italic;
|
||
}
|
||
.dsc-desc-link {
|
||
display: inline-flex; align-items: center; gap: 6px;
|
||
font-size: .7rem; font-weight: 600; color: var(--accent2);
|
||
text-decoration: none; padding: 6px 13px; border-radius: 999px;
|
||
background: rgba(0,245,255,.08); border: 1px solid rgba(0,245,255,.2);
|
||
transition: all .2s;
|
||
}
|
||
.dsc-desc-link:hover { background: rgba(0,245,255,.15); border-color: var(--accent2); }
|
||
</style>
|
||
@endpush
|
||
|
||
@section('content')
|
||
<div class="dsc-page" id="dscPage">
|
||
|
||
{{-- Ambient orbs --}}
|
||
<div class="dsc-orb dsc-orb-1" aria-hidden="true"></div>
|
||
<div class="dsc-orb dsc-orb-2" aria-hidden="true"></div>
|
||
|
||
{{-- Header --}}
|
||
<div class="dsc-header">
|
||
<a href="{{ route('home') }}" class="dsc-back">
|
||
<i class="bi bi-arrow-left" style="font-size:.9rem"></i>
|
||
</a>
|
||
<div class="dsc-heading">
|
||
<span class="dsc-heading-main">Keşfet</span>
|
||
<span class="dsc-heading-sub">Sana uygun animeyi bul</span>
|
||
</div>
|
||
<button class="dsc-filter-toggle" id="dscFilterToggle" title="Filtrele">
|
||
<i class="bi bi-sliders2"></i>
|
||
<span class="dsc-filter-dot" id="dscFilterDot"></span>
|
||
</button>
|
||
</div>
|
||
|
||
{{-- Filter panel --}}
|
||
<div class="dsc-filters" id="dscFilters">
|
||
<div class="dsc-fgroup">
|
||
<label>Tür</label>
|
||
<div class="dsc-fpills" id="dscGenrePills">
|
||
<button class="dfp active" data-genre="">Tümü</button>
|
||
@foreach($genres as $g)
|
||
<button class="dfp" data-genre="{{ $g->slug }}">{{ $g->name }}</button>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
<div class="dsc-fgroup">
|
||
<label>Format</label>
|
||
<div class="dsc-fpills" id="dscTypePills">
|
||
<button class="dfp active" data-type="">Tümü</button>
|
||
<button class="dfp" data-type="series">Dizi</button>
|
||
<button class="dfp" data-type="movie">Film</button>
|
||
<button class="dfp" data-type="ova">OVA</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Progress --}}
|
||
<div class="dsc-progress">
|
||
<div class="dsc-progress-bar">
|
||
<div class="dsc-progress-fill" id="dscProgFill"></div>
|
||
</div>
|
||
<span class="dsc-count-txt" id="dscCountTxt"></span>
|
||
</div>
|
||
|
||
{{-- Card stack --}}
|
||
<div class="dsc-stage">
|
||
<div class="dsc-stack" id="dscStack">
|
||
<div class="dsc-state" id="dscLoading">
|
||
<div class="dsc-splash" id="dscSplash">
|
||
|
||
{{-- Floating icons --}}
|
||
<div class="splash-floats" id="splashFloats"></div>
|
||
|
||
{{-- Logo --}}
|
||
<div class="splash-logo">Animexe Keşfet</div>
|
||
|
||
{{-- Spinning rings + center icon --}}
|
||
<div class="splash-ring-wrap">
|
||
<div class="splash-ring"></div>
|
||
<div class="splash-ring-2"></div>
|
||
<span class="splash-icon-center">♥</span>
|
||
</div>
|
||
|
||
{{-- Cycling messages --}}
|
||
<div class="splash-text-wrap" id="splashTextWrap">
|
||
<span class="splash-msg active" id="splashMsg">Animeler hazırlanıyor...</span>
|
||
</div>
|
||
<div class="splash-sub">Zevklerine göre seçiyoruz</div>
|
||
|
||
{{-- Dots --}}
|
||
<div class="splash-dots">
|
||
<div class="splash-dot"></div>
|
||
<div class="splash-dot"></div>
|
||
<div class="splash-dot"></div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
{{-- Results screen (replaces empty state) --}}
|
||
<div class="dsc-state" id="dscEmpty" style="display:none">
|
||
<div class="dsc-loader" id="dscResultsLoader"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Açıklama paneli --}}
|
||
<div class="dsc-desc-panel" id="dscDescPanel" style="display:none">
|
||
<button class="dsc-desc-toggle" id="dscDescToggle">
|
||
<span class="dsc-desc-toggle-icon"><i class="bi bi-chevron-down"></i></span>
|
||
<span class="dsc-desc-toggle-label">Açıklama</span>
|
||
<span class="dsc-desc-toggle-hint" id="dscDescHint"></span>
|
||
</button>
|
||
<div class="dsc-desc-body" id="dscDescBody">
|
||
<div class="dsc-desc-inner">
|
||
<div class="dsc-desc-anime-title" id="dscDescTitle"></div>
|
||
<p class="dsc-desc-text" id="dscDescText"></p>
|
||
<a class="dsc-desc-link" id="dscDescLink" href="#" target="_blank">
|
||
<i class="bi bi-box-arrow-up-right" style="font-size:.7rem"></i> Anime sayfası
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Action buttons --}}
|
||
<div class="dsc-actions" id="dscActions">
|
||
<button class="dsc-btn dsc-btn-skip" id="dscSkipBtn" disabled title="Geç ←">
|
||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.8" stroke-linecap="round">
|
||
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
|
||
</svg>
|
||
</button>
|
||
<button class="dsc-btn dsc-btn-info" id="dscInfoBtn" disabled title="Detaylar ↑">
|
||
<i class="bi bi-chevron-up" style="font-size:.9rem"></i>
|
||
</button>
|
||
<button class="dsc-btn dsc-btn-like" id="dscLikeBtn" disabled title="Listeme Ekle →">
|
||
<svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
|
||
{{-- Keyboard hint --}}
|
||
<div class="dsc-kbd">
|
||
<span><kbd>←</kbd> Geç</span>
|
||
<span><kbd>↑</kbd> Detaylar</span>
|
||
<span><kbd>→</kbd> Listeme Ekle</span>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
{{-- ─────────────────────────────────────────────────
|
||
BOTTOM SHEET
|
||
───────────────────────────────────────────────── --}}
|
||
<div class="bs-overlay" id="bsOverlay"></div>
|
||
<div class="bs-sheet" id="bsSheet" role="dialog" aria-modal="true" aria-label="Anime Detayları">
|
||
|
||
<div class="bs-handle-row" id="bsHandleRow">
|
||
<div class="bs-handle" id="bsHandle"></div>
|
||
</div>
|
||
|
||
<div class="bs-body" id="bsBody">
|
||
{{-- Banner --}}
|
||
<div id="bsBanner"></div>
|
||
|
||
<div class="bs-content">
|
||
<div class="bs-genres" id="bsGenres"></div>
|
||
<h2 class="bs-title" id="bsTitle"></h2>
|
||
<div class="bs-meta" id="bsMeta"></div>
|
||
<div class="bs-badges" id="bsBadges"></div>
|
||
|
||
<div class="bs-stats" id="bsStats"></div>
|
||
|
||
<div class="bs-divider"></div>
|
||
|
||
<div id="bsDescBlock">
|
||
<div class="bs-desc-title">Hakkında</div>
|
||
<p class="bs-desc" id="bsDesc"></p>
|
||
</div>
|
||
|
||
<a class="bs-detail-link" id="bsDetailLink" href="#" target="_blank">
|
||
<span>Anime sayfasına git</span>
|
||
<i class="bi bi-arrow-up-right" style="font-size:.78rem"></i>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bs-actions">
|
||
<button class="bs-act-skip" id="bsSkipBtn">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round">
|
||
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
|
||
</svg>
|
||
Geç
|
||
</button>
|
||
<button class="bs-act-like" id="bsLikeBtn">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>
|
||
</svg>
|
||
Listeme Ekle
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Match celebration overlay --}}
|
||
<div class="match-overlay" id="matchOverlay" style="display:none"></div>
|
||
@endsection
|
||
|
||
@push('scripts')
|
||
<script>
|
||
(function () {
|
||
'use strict';
|
||
|
||
/* ── Config ───────────────────────────────────────────── */
|
||
const SWIPE_THRESH = 88;
|
||
const ROT_FACTOR = 0.1;
|
||
const FETCH_AHEAD = 3;
|
||
const CSRF = document.querySelector('meta[name="csrf-token"]')?.content ?? '';
|
||
|
||
const TYPE_LABELS = { series:'Dizi', movie:'Film', ova:'OVA', ona:'ONA', special:'Özel' };
|
||
const STATUS_LABELS = { ongoing:'Devam Ediyor', completed:'Tamamlandı', finished:'Bitti', announced:'Duyuruldu' };
|
||
|
||
/* ── State ────────────────────────────────────────────── */
|
||
let buffer = [];
|
||
let shownCount = 0;
|
||
let fetching = false;
|
||
let fetchErrState = false;
|
||
let filters = { genre:'', type:'' };
|
||
let dragging = false, startX = 0, startY = 0, curDX = 0;
|
||
let topCard = null;
|
||
let currentData = null;
|
||
let firstLoad = true;
|
||
|
||
/* ── DOM ──────────────────────────────────────────────── */
|
||
const stack = document.getElementById('dscStack');
|
||
const loadingEl = document.getElementById('dscLoading');
|
||
const emptyEl = document.getElementById('dscEmpty');
|
||
const skipBtn = document.getElementById('dscSkipBtn');
|
||
const likeBtn = document.getElementById('dscLikeBtn');
|
||
const infoBtn = document.getElementById('dscInfoBtn');
|
||
const progFill = document.getElementById('dscProgFill');
|
||
const countTxt = document.getElementById('dscCountTxt');
|
||
const filterToggle= document.getElementById('dscFilterToggle');
|
||
const filterPanel = document.getElementById('dscFilters');
|
||
const filterDot = document.getElementById('dscFilterDot');
|
||
const matchEl = document.getElementById('matchOverlay');
|
||
|
||
/* ── Sheet DOM ────────────────────────────────────────── */
|
||
const bsOverlay = document.getElementById('bsOverlay');
|
||
const bsSheet = document.getElementById('bsSheet');
|
||
const bsBody = document.getElementById('bsBody');
|
||
const bsHandleRow= document.getElementById('bsHandleRow');
|
||
const bsSkipBtn = document.getElementById('bsSkipBtn');
|
||
const bsLikeBtn = document.getElementById('bsLikeBtn');
|
||
|
||
/* ── Desc panel DOM ───────────────────────────────────── */
|
||
const descPanel = document.getElementById('dscDescPanel');
|
||
const descToggle = document.getElementById('dscDescToggle');
|
||
const descBody = document.getElementById('dscDescBody');
|
||
const descTitle = document.getElementById('dscDescTitle');
|
||
const descText = document.getElementById('dscDescText');
|
||
const descHint = document.getElementById('dscDescHint');
|
||
const descLink = document.getElementById('dscDescLink');
|
||
let descOpen = false;
|
||
|
||
/* ══════════════════════════════════════════════════════
|
||
CARD LOGIC
|
||
══════════════════════════════════════════════════════ */
|
||
|
||
async function fetchCards(limit = 8) {
|
||
if (fetching) return;
|
||
fetching = true;
|
||
try {
|
||
const ctrl = new AbortController();
|
||
const timer = setTimeout(() => ctrl.abort(), 10000); // 10sn timeout
|
||
const p = new URLSearchParams({ limit, ...filters });
|
||
const r = await fetch(`/kesfet/cards?${p}`, {
|
||
headers: { Accept:'application/json' },
|
||
signal: ctrl.signal,
|
||
});
|
||
clearTimeout(timer);
|
||
const d = await r.json();
|
||
if (d.error) { showFetchError(); return; }
|
||
if (d.cards?.length) buffer.push(...d.cards);
|
||
} catch(e) {
|
||
if (e.name === 'AbortError') {
|
||
showFetchError();
|
||
} else {
|
||
console.warn('[Keşfet]', e);
|
||
showFetchError();
|
||
}
|
||
} finally { fetching = false; }
|
||
}
|
||
|
||
function showFetchError() {
|
||
fetchErrState = true;
|
||
setLoading(false);
|
||
const splash = document.getElementById('dscSplash');
|
||
if (splash) {
|
||
splash.innerHTML = `
|
||
<div style="text-align:center;padding:20px">
|
||
<div style="font-size:2.2rem;margin-bottom:14px;color:#ff2d7d">⚠</div>
|
||
<div style="font-size:.9rem;font-weight:700;color:var(--text);margin-bottom:8px">Yüklenemedi</div>
|
||
<div style="font-size:.72rem;color:var(--text3);margin-bottom:20px;line-height:1.6">Sunucu yanıt vermedi.<br>İnternet bağlantını kontrol et.</div>
|
||
<button onclick="window.location.reload()" style="
|
||
padding:10px 22px;border-radius:999px;border:1px solid rgba(0,245,255,.4);
|
||
background:rgba(0,245,255,.08);color:#00f5ff;font-size:.8rem;
|
||
font-weight:600;cursor:pointer;font-family:inherit">
|
||
Tekrar Dene
|
||
</button>
|
||
</div>`;
|
||
loadingEl.style.display = 'flex';
|
||
}
|
||
}
|
||
|
||
function makeCard(data, animate = false) {
|
||
const el = document.createElement('div');
|
||
el.className = 'dsc-card' + (animate ? ' entering' : '');
|
||
el.dataset.id = data.id; el.dataset.slug = data.slug;
|
||
if (animate) el.addEventListener('animationend', () => el.classList.remove('entering'), { once:true });
|
||
|
||
const imgSrc = data.banner_url || data.cover_url || '';
|
||
const genres = (data.genres || []).slice(0,3)
|
||
.map(g => `<span class="dsc-genre-pill">${esc(g)}</span>`).join('');
|
||
|
||
const starHtml = data.rating
|
||
? `<span class="dsc-card-star">
|
||
<svg viewBox="0 0 24 24"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>
|
||
${data.rating}
|
||
</span>` : '';
|
||
const metaParts = [
|
||
data.year ? `<span>${data.year}</span>` : '',
|
||
data.episode_count ? `<span>${data.episode_count} bölüm</span>` : '',
|
||
starHtml,
|
||
].filter(Boolean);
|
||
|
||
el.innerHTML = `
|
||
<div class="dsc-card-img">
|
||
${imgSrc
|
||
? `<img src="${imgSrc}" alt="" draggable="false" loading="eager">`
|
||
: `<div class="dsc-card-noimg"><i class="bi bi-film"></i></div>`}
|
||
<div class="dsc-card-gradient"></div>
|
||
</div>
|
||
<div class="dsc-card-tint"></div>
|
||
<span class="dsc-stamp dsc-stamp-like">Listeme Ekle</span>
|
||
<span class="dsc-stamp dsc-stamp-skip">Geç</span>
|
||
<div class="dsc-card-info">
|
||
<div class="dsc-card-genres">${genres}</div>
|
||
<h2 class="dsc-card-title">${esc(data.title)}</h2>
|
||
<div class="dsc-card-meta">${metaParts.join('')}</div>
|
||
${data.hook ? `<p class="dsc-card-hook">${esc(data.hook)}</p>` : ''}
|
||
</div>
|
||
`;
|
||
return el;
|
||
}
|
||
|
||
function renderStack() {
|
||
stack.querySelectorAll('.dsc-card').forEach(c => c.remove());
|
||
if (!buffer.length) {
|
||
if (!fetchErrState) { setLoading(false); showEmpty(); }
|
||
return;
|
||
}
|
||
fetchErrState = false;
|
||
|
||
const visible = buffer.slice(0, 3);
|
||
[...visible].reverse().forEach((data, i) => {
|
||
const el = makeCard(data, i === visible.length - 1 && firstLoad);
|
||
stack.appendChild(el);
|
||
});
|
||
if (firstLoad) {
|
||
firstLoad = false;
|
||
// Tap hint on the first card
|
||
const hint = document.createElement('div');
|
||
hint.className = 'dsc-hint-pill';
|
||
hint.textContent = 'Kaydırarak keşfet';
|
||
stack.querySelector('.pos-0, .dsc-card:last-child')?.appendChild(hint);
|
||
}
|
||
|
||
assignPositions();
|
||
bindTopCard();
|
||
updateUI();
|
||
setLoading(false);
|
||
emptyEl.style.display = 'none';
|
||
}
|
||
|
||
function assignPositions() {
|
||
const cards = Array.from(stack.querySelectorAll('.dsc-card'));
|
||
cards.forEach(c => c.classList.remove('pos-0','pos-1','pos-2'));
|
||
if (cards[cards.length-1]) cards[cards.length-1].classList.add('pos-0');
|
||
if (cards[cards.length-2]) cards[cards.length-2].classList.add('pos-1');
|
||
if (cards[cards.length-3]) cards[cards.length-3].classList.add('pos-2');
|
||
}
|
||
|
||
function bindTopCard() {
|
||
topCard = stack.querySelector('.pos-0');
|
||
currentData = topCard ? buffer[0] : null;
|
||
if (!topCard) return;
|
||
topCard.addEventListener('mousedown', onDragStart, { passive:false });
|
||
topCard.addEventListener('touchstart', onDragStart, { passive:true });
|
||
}
|
||
|
||
/* ── Drag ─────────────────────────────────────────────── */
|
||
function onDragStart(e) {
|
||
if (bsSheet.classList.contains('open')) return;
|
||
dragging = true;
|
||
startX = e.type === 'touchstart' ? e.touches[0].clientX : e.clientX;
|
||
startY = e.type === 'touchstart' ? e.touches[0].clientY : e.clientY;
|
||
curDX = 0;
|
||
if (topCard) topCard.style.transition = 'none';
|
||
}
|
||
|
||
function onDragMove(e) {
|
||
if (!dragging || !topCard) return;
|
||
const cx = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX;
|
||
curDX = cx - startX;
|
||
const dy = (e.type === 'touchmove' ? e.touches[0].clientY : e.clientY) - startY;
|
||
const rot = curDX * ROT_FACTOR;
|
||
const lift= Math.abs(curDX) * 0.025;
|
||
|
||
topCard.style.transform = `translateX(${curDX}px) translateY(${-lift}px) rotate(${rot}deg)`;
|
||
|
||
// Stamp hints
|
||
if (curDX > 30) { topCard.classList.add('hint-like'); topCard.classList.remove('hint-skip'); }
|
||
else if (curDX < -30) { topCard.classList.add('hint-skip'); topCard.classList.remove('hint-like'); }
|
||
else { topCard.classList.remove('hint-like','hint-skip'); }
|
||
|
||
// Promote second card
|
||
const second = stack.querySelector('.pos-1');
|
||
if (second) {
|
||
const p = Math.min(Math.abs(curDX) / SWIPE_THRESH, 1);
|
||
second.style.transition = 'none';
|
||
second.style.transform = `scale(${0.95 + p*.05}) translateY(${18 - p*18}px)`;
|
||
}
|
||
}
|
||
|
||
function onDragEnd() {
|
||
if (!dragging) return;
|
||
dragging = false;
|
||
if (!topCard) return;
|
||
if (curDX > SWIPE_THRESH) commitSwipe('like');
|
||
else if (curDX < -SWIPE_THRESH) commitSwipe('skip');
|
||
else snapBack();
|
||
}
|
||
|
||
function snapBack() {
|
||
if (!topCard) return;
|
||
topCard.classList.remove('hint-like','hint-skip');
|
||
topCard.style.transition = 'transform .38s cubic-bezier(.175,.885,.32,1.275)';
|
||
topCard.style.transform = '';
|
||
const second = stack.querySelector('.pos-1');
|
||
if (second) {
|
||
second.style.transition = 'transform .38s cubic-bezier(.175,.885,.32,1.275)';
|
||
second.style.transform = 'scale(.95) translateY(18px)';
|
||
}
|
||
}
|
||
|
||
/* ── Commit swipe ─────────────────────────────────────── */
|
||
function commitSwipe(dir) {
|
||
if (!topCard) return;
|
||
|
||
const animeId = parseInt(topCard.dataset.id);
|
||
topCard.classList.remove('hint-like','hint-skip');
|
||
topCard.classList.add(dir === 'like' ? 'going-right' : 'going-left');
|
||
|
||
if (dir === 'like') {
|
||
likeBtn.classList.add('pulse');
|
||
setTimeout(() => likeBtn.classList.remove('pulse'), 300);
|
||
triggerMatchAnim();
|
||
}
|
||
|
||
shownCount++;
|
||
buffer.shift();
|
||
closeDesc();
|
||
|
||
setTimeout(() => {
|
||
topCard?.remove();
|
||
topCard = null;
|
||
currentData = null;
|
||
|
||
if (!buffer.length) {
|
||
showEmpty();
|
||
return;
|
||
}
|
||
|
||
// Add 3rd card if buffer has it
|
||
if (buffer[2] && !stack.querySelector(`[data-id="${buffer[2].id}"]`)) {
|
||
const el = makeCard(buffer[2], true);
|
||
stack.prepend(el);
|
||
}
|
||
|
||
assignPositions();
|
||
bindTopCard();
|
||
updateUI();
|
||
}, 400);
|
||
|
||
postSwipe(animeId, dir);
|
||
}
|
||
|
||
async function postSwipe(id, dir) {
|
||
try {
|
||
await fetch('/kesfet/swipe', {
|
||
method:'POST',
|
||
headers:{ 'Content-Type':'application/json', 'X-CSRF-TOKEN':CSRF, Accept:'application/json' },
|
||
body: JSON.stringify({ anime_id:id, direction:dir }),
|
||
});
|
||
} catch {}
|
||
}
|
||
|
||
/* ── UI helpers ───────────────────────────────────────── */
|
||
function updateUI() {
|
||
const has = !!buffer.length;
|
||
skipBtn.disabled = !has; likeBtn.disabled = !has; infoBtn.disabled = !has;
|
||
countTxt.textContent = has ? `${shownCount + 1}. kart` : '';
|
||
const total = shownCount + buffer.length;
|
||
progFill.style.width = total > 0 ? `${Math.min((shownCount / total) * 100, 95)}%` : '0%';
|
||
updateDescPanel();
|
||
}
|
||
|
||
function updateDescPanel() {
|
||
if (!currentData) {
|
||
descPanel.style.display = 'none';
|
||
closeDesc();
|
||
return;
|
||
}
|
||
descPanel.style.display = '';
|
||
const text = currentData.description || currentData.hook || '';
|
||
descTitle.textContent = currentData.title;
|
||
descText.textContent = text;
|
||
descHint.textContent = text ? text.slice(0, 55) + '…' : 'Açıklama yok';
|
||
descLink.href = `/anime/${currentData.slug}`;
|
||
if (!text) {
|
||
descText.innerHTML = '<span class="dsc-desc-empty">Bu anime için açıklama bulunamadı.</span>';
|
||
}
|
||
}
|
||
|
||
function closeDesc() {
|
||
descOpen = false;
|
||
descToggle.classList.remove('open');
|
||
descBody.classList.remove('open');
|
||
}
|
||
|
||
descToggle.addEventListener('click', () => {
|
||
descOpen = !descOpen;
|
||
descToggle.classList.toggle('open', descOpen);
|
||
descBody.classList.toggle('open', descOpen);
|
||
});
|
||
|
||
function setLoading(v) {
|
||
loadingEl.style.display = v ? 'flex' : 'none';
|
||
if (!v && window._dscStopSplash) window._dscStopSplash();
|
||
}
|
||
|
||
function showEmpty() {
|
||
emptyEl.style.display = 'flex';
|
||
skipBtn.disabled = likeBtn.disabled = infoBtn.disabled = true;
|
||
countTxt.textContent = '';
|
||
progFill.style.width = '100%';
|
||
descPanel.style.display = 'none';
|
||
closeDesc();
|
||
loadResults();
|
||
}
|
||
|
||
async function loadResults() {
|
||
try {
|
||
const ctrl = new AbortController();
|
||
const timer = setTimeout(() => ctrl.abort(), 15000);
|
||
const r = await fetch('/kesfet/results', {
|
||
headers: { Accept:'application/json' },
|
||
signal: ctrl.signal,
|
||
});
|
||
clearTimeout(timer);
|
||
const d = await r.json();
|
||
renderResults(d);
|
||
} catch {
|
||
renderResultsFallback();
|
||
}
|
||
}
|
||
|
||
function renderResults(d) {
|
||
// Remove existing results overlay if any
|
||
document.getElementById('dscResultsOverlay')?.remove();
|
||
|
||
const isAuth = d.is_auth;
|
||
const liked = d.liked || [];
|
||
const recs = d.recommendations || [];
|
||
const likeCount = d.like_count ?? liked.length;
|
||
const skipCount = d.skip_count ?? 0;
|
||
|
||
// Build liked posters HTML
|
||
const likedHtml = liked.length
|
||
? liked.map(a => `
|
||
<a class="res-liked-card" href="/anime/${a.slug}" target="_blank" title="${esc(a.title)}">
|
||
<div class="res-liked-poster">
|
||
${a.cover_url
|
||
? `<img src="${a.cover_url}" alt="${esc(a.title)}" loading="lazy">`
|
||
: `<div class="res-liked-poster-ph"><i class="bi bi-film"></i></div>`}
|
||
<div class="res-liked-heart"><i class="bi bi-heart-fill"></i></div>
|
||
</div>
|
||
<div class="res-liked-name">${esc(a.title)}</div>
|
||
</a>`).join('')
|
||
: `<p style="font-size:.76rem;color:var(--text3);font-style:italic;padding:6px 0">Hiç anime beğenmedin.</p>`;
|
||
|
||
// Build recs HTML
|
||
const recsHtml = recs.length
|
||
? recs.map(a => `
|
||
<a class="res-rec-card" href="/anime/${a.slug}" target="_blank">
|
||
<div class="res-rec-cover">
|
||
${a.cover_url
|
||
? `<img src="${a.cover_url}" alt="${esc(a.title)}" loading="lazy">`
|
||
: `<div class="res-rec-cover-ph"><i class="bi bi-film"></i></div>`}
|
||
</div>
|
||
<div class="res-rec-body">
|
||
<div class="res-rec-title">${esc(a.title)}</div>
|
||
<div class="res-rec-meta">
|
||
${a.rating ? `<span class="star"><i class="bi bi-star-fill" style="font-size:.55rem"></i> ${a.rating}</span>` : ''}
|
||
${a.year ? `<span>${a.year}</span>` : ''}
|
||
</div>
|
||
${(a.genres||[]).length ? `<div class="res-rec-genres">${a.genres.map(g=>`<span class="res-rec-genre">${esc(g)}</span>`).join('')}</div>` : ''}
|
||
${a.reason ? `<div class="res-rec-reason" style="margin-top:6px">${esc(a.reason)}</div>` : ''}
|
||
</div>
|
||
</a>`).join('')
|
||
: `<p style="font-size:.76rem;color:var(--text3);font-style:italic;padding:6px 0">Öneri üretilemedi.</p>`;
|
||
|
||
// Where to find section
|
||
const findSteps = isAuth ? `
|
||
<div class="res-find-step">
|
||
<div class="res-find-num">1</div>
|
||
<div class="res-find-text">Beğendiğin animeler otomatik olarak <strong>İzleme Listene</strong> eklendi (İzlemek İstiyorum olarak).</div>
|
||
</div>
|
||
<div class="res-find-step">
|
||
<div class="res-find-num">2</div>
|
||
<div class="res-find-text"><a href="/profile">Profil sayfana</a> git → <strong>Listem</strong> sekmesine tıkla → Tüm beğendiklerini göreceksin.</div>
|
||
</div>
|
||
<div class="res-find-step">
|
||
<div class="res-find-num">3</div>
|
||
<div class="res-find-text">Keşfet geçmişine bakmak için <strong>Profil → Keşfet</strong> sekmesini kullan — beğenilenler ve geçilenler ayrı görünür.</div>
|
||
</div>
|
||
<div class="res-find-step">
|
||
<div class="res-find-num">4</div>
|
||
<div class="res-find-text">Bir animenin adına tıklayarak <strong>anime sayfasına</strong> gidebilir ve izlemeye başlayabilirsin.</div>
|
||
</div>` : `
|
||
<div class="res-find-step">
|
||
<div class="res-find-num">1</div>
|
||
<div class="res-find-text">Şu an misafir olarak kullanıyorsun. Beğenilerin <strong>kaydedilmedi</strong>.</div>
|
||
</div>
|
||
<div class="res-find-step">
|
||
<div class="res-find-num">2</div>
|
||
<div class="res-find-text"><a href="/register">Ücretsiz kayıt ol</a> ya da <a href="/login">giriş yap</a> — beğenilerin İzleme Listene otomatik eklensin.</div>
|
||
</div>`;
|
||
|
||
const guestNotice = !isAuth ? `
|
||
<div class="res-guest-notice">
|
||
⚠️ Misafir olarak kullanıyorsun — beğenilerin kaydedilmedi.
|
||
<a href="/register">Kayıt ol</a> ya da <a href="/login">giriş yap</a> ve tekrar keşfet.
|
||
</div>` : '';
|
||
|
||
const overlay = document.createElement('div');
|
||
overlay.id = 'dscResultsOverlay';
|
||
overlay.className = 'dsc-results-overlay';
|
||
overlay.innerHTML = `
|
||
<div class="res-wrap">
|
||
|
||
<div class="res-header">
|
||
<span class="res-trophy">🎉</span>
|
||
<div class="res-title">Keşif Tamamlandı!</div>
|
||
<div class="res-subtitle">Bu tur bitti — işte özeting</div>
|
||
</div>
|
||
|
||
<div class="res-stats">
|
||
<div class="res-stat">
|
||
<span class="res-stat-val like">${likeCount}</span>
|
||
<span class="res-stat-label">♥ Beğendin</span>
|
||
</div>
|
||
<div class="res-stat">
|
||
<span class="res-stat-val skip">${skipCount}</span>
|
||
<span class="res-stat-label">✕ Geçtin</span>
|
||
</div>
|
||
</div>
|
||
|
||
${guestNotice}
|
||
|
||
${liked.length ? `
|
||
<div class="res-sec">
|
||
<div class="res-sec-title cyan">Beğendiklerin</div>
|
||
<div class="res-liked-strip">${likedHtml}</div>
|
||
</div>` : ''}
|
||
|
||
<div class="res-sec">
|
||
<div class="res-sec-title purple">Yapay Zeka Önerileri</div>
|
||
<div class="res-recs">${recsHtml}</div>
|
||
</div>
|
||
|
||
<div class="res-sec">
|
||
<div class="res-find-box">
|
||
<div class="res-find-title"><i class="bi bi-compass-fill"></i> Beğendiklerime Nereden Ulaşırım?</div>
|
||
<div class="res-find-steps">${findSteps}</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="res-actions">
|
||
<button class="res-btn-continue" id="resContinueBtn">
|
||
<i class="bi bi-arrow-clockwise"></i> Daha Fazla Anime Keşfet
|
||
</button>
|
||
${isAuth
|
||
? `<a class="res-btn-profile" href="/profile"><i class="bi bi-person-circle"></i> Profilime Git → Listem</a>`
|
||
: `<a class="res-btn-profile" href="/register"><i class="bi bi-person-plus"></i> Kayıt Ol — Listeni Kaydet</a>`
|
||
}
|
||
</div>
|
||
|
||
</div>`;
|
||
|
||
document.body.appendChild(overlay);
|
||
emptyEl.style.display = 'none';
|
||
|
||
document.getElementById('resContinueBtn')?.addEventListener('click', async () => {
|
||
overlay.style.animation = 'resultsFadeIn .3s cubic-bezier(.22,1,.36,1) reverse forwards';
|
||
await new Promise(r => setTimeout(r, 280));
|
||
overlay.remove();
|
||
restart();
|
||
});
|
||
}
|
||
|
||
function renderResultsFallback() {
|
||
emptyEl.innerHTML = `
|
||
<div style="text-align:center;padding:20px">
|
||
<div style="font-size:2.2rem;margin-bottom:14px">✓</div>
|
||
<div style="font-size:1rem;font-weight:700;color:var(--text);margin-bottom:8px">Hepsini gördün!</div>
|
||
<div style="font-size:.76rem;color:var(--text3);margin-bottom:20px">Tüm animeleri kaydırdın.</div>
|
||
<button class="dsc-restart" id="dscRestartBtn"><i class="bi bi-arrow-clockwise"></i> Yeniden başla</button>
|
||
</div>`;
|
||
document.getElementById('dscRestartBtn')?.addEventListener('click', restart);
|
||
}
|
||
|
||
/* ── Match animation ──────────────────────────────────── */
|
||
function triggerMatchAnim() {
|
||
matchEl.style.display = 'flex';
|
||
matchEl.innerHTML = `
|
||
<div class="match-heart">♥</div>
|
||
<div class="match-text">Listene Eklendi!</div>
|
||
`;
|
||
// Spawn particles
|
||
const colors = ['#00f5ff','#b84dff','#00f5ff','#fff'];
|
||
for (let i = 0; i < 14; i++) {
|
||
const p = document.createElement('div');
|
||
p.className = 'sp-particle';
|
||
const ang = (i / 14) * 360;
|
||
const dist = 80 + Math.random() * 80;
|
||
const rad = (ang * Math.PI) / 180;
|
||
const tx = Math.cos(rad) * dist;
|
||
const ty = Math.sin(rad) * dist;
|
||
p.style.cssText = `
|
||
left:50%; top:45%;
|
||
margin:-3px;
|
||
background:${colors[i % colors.length]};
|
||
--fly: translate(${tx}px,${ty}px);
|
||
animation-delay:${i * 0.03}s;
|
||
`;
|
||
matchEl.appendChild(p);
|
||
}
|
||
setTimeout(() => { matchEl.style.display = 'none'; matchEl.innerHTML = ''; }, 1100);
|
||
}
|
||
|
||
/* ── Boot & restart ───────────────────────────────────── */
|
||
async function init() {
|
||
setLoading(true);
|
||
await fetchCards(10);
|
||
renderStack();
|
||
}
|
||
|
||
async function restart() {
|
||
document.getElementById('dscResultsOverlay')?.remove();
|
||
buffer = []; shownCount = 0; firstLoad = false; fetchErrState = false; fetching = false;
|
||
stack.querySelectorAll('.dsc-card').forEach(c => c.remove());
|
||
emptyEl.style.display = 'none';
|
||
setLoading(true);
|
||
try { await fetch('/kesfet/reset', { method:'POST', headers:{ 'X-CSRF-TOKEN':CSRF } }); } catch {}
|
||
await fetchCards(10);
|
||
renderStack();
|
||
}
|
||
|
||
/* ══════════════════════════════════════════════════════
|
||
BOTTOM SHEET
|
||
══════════════════════════════════════════════════════ */
|
||
|
||
function openSheet() {
|
||
if (!currentData) return;
|
||
populateSheet(currentData);
|
||
bsBody.scrollTop = 0;
|
||
bsOverlay.classList.add('open');
|
||
bsSheet.classList.add('open');
|
||
document.body.style.overflow = 'hidden';
|
||
}
|
||
|
||
function closeSheet() {
|
||
bsSheet.classList.remove('open');
|
||
bsOverlay.classList.remove('open');
|
||
document.body.style.overflow = '';
|
||
}
|
||
|
||
function populateSheet(d) {
|
||
// Banner
|
||
const bannerEl = document.getElementById('bsBanner');
|
||
if (d.banner_url || d.cover_url) {
|
||
bannerEl.innerHTML = `
|
||
<div class="bs-banner">
|
||
<img src="${d.banner_url || d.cover_url}" alt="${esc(d.title)}" loading="lazy">
|
||
<div class="bs-banner-grad"></div>
|
||
</div>`;
|
||
} else {
|
||
bannerEl.innerHTML = `<div class="bs-banner-ph"><i class="bi bi-film"></i></div>`;
|
||
}
|
||
|
||
// Genres
|
||
document.getElementById('bsGenres').innerHTML =
|
||
(d.genres || []).map(g => `<span class="bs-genre-pill">${esc(g)}</span>`).join('');
|
||
|
||
// Title
|
||
document.getElementById('bsTitle').textContent = d.title;
|
||
|
||
// Meta
|
||
const metaArr = [];
|
||
if (d.rating) metaArr.push(`<span class="bs-meta-star">
|
||
<svg viewBox="0 0 24 24"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>
|
||
${d.rating}</span>`);
|
||
if (d.year) metaArr.push(`<span>${d.year}</span>`);
|
||
if (d.episode_count) metaArr.push(`<span>${d.episode_count} bölüm</span>`);
|
||
document.getElementById('bsMeta').innerHTML = metaArr.join('');
|
||
|
||
// Badges
|
||
const badges = [];
|
||
if (d.type) badges.push(`<span class="bs-badge bs-badge-type">${TYPE_LABELS[d.type] || d.type}</span>`);
|
||
if (d.status) badges.push(`<span class="bs-badge bs-badge-status">${STATUS_LABELS[d.status] || d.status}</span>`);
|
||
document.getElementById('bsBadges').innerHTML = badges.join('');
|
||
|
||
// Stats
|
||
const statsHtml = [
|
||
{ val: d.year || '—', label: 'Yıl' },
|
||
{ val: d.episode_count || '—', label: 'Bölüm' },
|
||
{ val: d.rating || '—', label: 'Puan' },
|
||
].map(s => `
|
||
<div class="bs-stat">
|
||
<span class="bs-stat-val">${s.val}</span>
|
||
<span class="bs-stat-label">${s.label}</span>
|
||
</div>`).join('');
|
||
document.getElementById('bsStats').innerHTML = statsHtml;
|
||
|
||
// Description
|
||
const descText = d.description || d.hook || '';
|
||
const descBlock = document.getElementById('bsDescBlock');
|
||
if (descText) {
|
||
descBlock.style.display = '';
|
||
document.getElementById('bsDesc').textContent = descText;
|
||
} else {
|
||
descBlock.style.display = 'none';
|
||
}
|
||
|
||
// Detail link
|
||
document.getElementById('bsDetailLink').href = `/anime/${d.slug}`;
|
||
}
|
||
|
||
// Sheet skip/like from within the sheet
|
||
bsSkipBtn.addEventListener('click', () => { closeSheet(); setTimeout(() => commitSwipe('skip'), 200); });
|
||
bsLikeBtn.addEventListener('click', () => { closeSheet(); setTimeout(() => commitSwipe('like'), 200); });
|
||
|
||
// Close on overlay click
|
||
bsOverlay.addEventListener('click', closeSheet);
|
||
|
||
// Drag-to-dismiss the sheet
|
||
let sheetDragStart = 0, sheetDragging = false, sheetTranslate = 0;
|
||
|
||
bsHandleRow.addEventListener('touchstart', e => {
|
||
sheetDragStart = e.touches[0].clientY;
|
||
sheetDragging = true;
|
||
sheetTranslate = 0;
|
||
bsSheet.style.transition = 'none';
|
||
}, { passive:true });
|
||
|
||
document.addEventListener('touchmove', e => {
|
||
if (!sheetDragging) return;
|
||
const dy = e.touches[0].clientY - sheetDragStart;
|
||
if (dy < 0) return;
|
||
sheetTranslate = dy;
|
||
bsSheet.style.transform = `translateY(${dy}px)`;
|
||
}, { passive:true });
|
||
|
||
document.addEventListener('touchend', () => {
|
||
if (!sheetDragging) return;
|
||
sheetDragging = false;
|
||
bsSheet.style.transition = '';
|
||
bsSheet.style.transform = '';
|
||
if (sheetTranslate > 120) closeSheet();
|
||
}, { passive:true });
|
||
|
||
/* ══════════════════════════════════════════════════════
|
||
GLOBAL EVENTS
|
||
══════════════════════════════════════════════════════ */
|
||
document.addEventListener('mousemove', onDragMove);
|
||
document.addEventListener('touchmove', onDragMove, { passive:true });
|
||
document.addEventListener('mouseup', onDragEnd);
|
||
document.addEventListener('touchend', onDragEnd);
|
||
|
||
skipBtn.addEventListener('click', () => { if (!skipBtn.disabled) commitSwipe('skip'); });
|
||
likeBtn.addEventListener('click', () => { if (!likeBtn.disabled) commitSwipe('like'); });
|
||
infoBtn.addEventListener('click', openSheet);
|
||
|
||
document.addEventListener('keydown', e => {
|
||
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
|
||
if (bsSheet.classList.contains('open')) {
|
||
if (e.key === 'Escape') closeSheet();
|
||
return;
|
||
}
|
||
if (e.key === 'ArrowRight' || e.key === 'l') { if (!likeBtn.disabled) commitSwipe('like'); }
|
||
else if (e.key === 'ArrowLeft' || e.key === 'h') { if (!skipBtn.disabled) commitSwipe('skip'); }
|
||
else if (e.key === 'ArrowUp' || e.key === 'i' || e.key === 'I') openSheet();
|
||
});
|
||
|
||
document.getElementById('dscRestartBtn')?.addEventListener('click', restart);
|
||
|
||
filterToggle.addEventListener('click', () => {
|
||
filterToggle.classList.toggle('active');
|
||
filterPanel.classList.toggle('open');
|
||
});
|
||
|
||
document.querySelectorAll('#dscGenrePills .dfp').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
document.querySelectorAll('#dscGenrePills .dfp').forEach(b => b.classList.remove('active'));
|
||
btn.classList.add('active');
|
||
filters.genre = btn.dataset.genre;
|
||
updateFilterDot();
|
||
resetAndLoad();
|
||
});
|
||
});
|
||
|
||
document.querySelectorAll('#dscTypePills .dfp').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
document.querySelectorAll('#dscTypePills .dfp').forEach(b => b.classList.remove('active'));
|
||
btn.classList.add('active');
|
||
filters.type = btn.dataset.type;
|
||
updateFilterDot();
|
||
resetAndLoad();
|
||
});
|
||
});
|
||
|
||
function updateFilterDot() {
|
||
filterDot.classList.toggle('on', !!(filters.genre || filters.type));
|
||
}
|
||
|
||
async function resetAndLoad() {
|
||
buffer = []; shownCount = 0; fetchErrState = false;
|
||
stack.querySelectorAll('.dsc-card').forEach(c => c.remove());
|
||
emptyEl.style.display = 'none';
|
||
setLoading(true);
|
||
await fetchCards(10);
|
||
renderStack();
|
||
}
|
||
|
||
/* ── Helpers ─────────────────────────────────────────── */
|
||
function esc(s) {
|
||
return String(s ?? '').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||
}
|
||
|
||
/* ══════════════════════════════════════════════════════
|
||
SPLASH SCREEN
|
||
══════════════════════════════════════════════════════ */
|
||
(function initSplash() {
|
||
const msgs = [
|
||
'Animeler hazırlanıyor...',
|
||
'En iyi seçimler seçiliyor...',
|
||
'Zevklerine göre sıralanıyor...',
|
||
'Yapay zeka çalışıyor...',
|
||
'Sürprizler yükleniyor...',
|
||
'Az kaldı, neredeyse hazır...',
|
||
];
|
||
|
||
const floatIcons = [
|
||
{ ch: '♥', color: '#00f5ff' },
|
||
{ ch: '✕', color: '#ff2d7d' },
|
||
{ ch: '♥', color: '#b84dff' },
|
||
{ ch: '★', color: '#fbbf24' },
|
||
{ ch: '♥', color: '#00f5ff' },
|
||
{ ch: '✕', color: '#ff2d7d' },
|
||
{ ch: '◆', color: '#00f5ff' },
|
||
{ ch: '♥', color: '#b84dff' },
|
||
{ ch: '✕', color: '#ff2d7d' },
|
||
{ ch: '♥', color: '#00f5ff' },
|
||
];
|
||
|
||
const floatContainer = document.getElementById('splashFloats');
|
||
const msgEl = document.getElementById('splashMsg');
|
||
|
||
if (!floatContainer || !msgEl) return;
|
||
|
||
// Spawn floating icons
|
||
floatIcons.forEach((ic, i) => {
|
||
const el = document.createElement('span');
|
||
el.className = 'sf-icon';
|
||
el.textContent = ic.ch;
|
||
el.style.cssText = `
|
||
left: ${8 + (i / floatIcons.length) * 85}%;
|
||
color: ${ic.color};
|
||
animation-duration: ${2.8 + Math.random() * 2.4}s;
|
||
animation-delay: ${i * 0.28 + Math.random() * 0.4}s;
|
||
font-size: ${1.1 + Math.random() * .8}rem;
|
||
`;
|
||
floatContainer.appendChild(el);
|
||
});
|
||
|
||
// Cycle messages
|
||
let msgIdx = 0;
|
||
const cycleMsg = setInterval(() => {
|
||
msgIdx = (msgIdx + 1) % msgs.length;
|
||
msgEl.classList.remove('active');
|
||
msgEl.classList.add('exit');
|
||
setTimeout(() => {
|
||
msgEl.textContent = msgs[msgIdx];
|
||
msgEl.classList.remove('exit');
|
||
msgEl.classList.add('active');
|
||
}, 420);
|
||
}, 1800);
|
||
|
||
// Stop cycling when loading ends
|
||
const orig = window._dscStopSplash;
|
||
window._dscStopSplash = function () {
|
||
clearInterval(cycleMsg);
|
||
if (orig) orig();
|
||
};
|
||
})();
|
||
|
||
init();
|
||
|
||
})();
|
||
</script>
|
||
@endpush
|