2026-05-29 00:33:00 +03:00
<! DOCTYPE html >
2026-05-29 09:37:07 +03:00
< html lang = "{{ str_replace('_', '-', app()->getLocale()) }}" class = "dark h-full" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< meta name = "csrf-token" content = "{{ csrf_token() }}" >
2026-05-31 14:19:47 +03:00
< title >@ yield ( 'title' , 'LoreKeepers — Track Every Game You Play' ) </ title >
< meta name = "description" content = "@yield('description', 'LoreKeepers lets you track every game you play, rate your favorites, and discover what to play next.')" >
2026-05-29 09:37:07 +03:00
@ hasSection ( 'canonical' )
< link rel = "canonical" href = "@yield('canonical')" >
@ endif
2026-05-29 00:33:00 +03:00
2026-05-29 09:37:07 +03:00
<!-- Open Graph -->
2026-05-31 14:19:47 +03:00
< meta property = "og:title" content = "@yield('og_title', 'LoreKeepers — Track, Rate & Discover Video Games')" >
2026-05-30 02:50:34 +03:00
< meta property = "og:description" content = "@yield('og_description', 'Track every game you play. Rate, review, and discover new games.')" >
< meta property = "og:image" content = "@yield('og_image', asset('images/og-default.jpg'))" >
2026-05-29 09:37:07 +03:00
< meta property = "og:type" content = "@yield('og_type', 'website')" >
< meta property = "og:url" content = "@yield('og_url', url()->current())" >
2026-05-30 02:50:34 +03:00
< meta name = "twitter:card" content = "summary_large_image" >
2026-05-29 00:33:00 +03:00
2026-05-29 09:37:07 +03:00
<!-- Fonts -->
< link rel = "preconnect" href = "https://fonts.bunny.net" >
< link href = "https://fonts.bunny.net/css?family=figtree:400,500,600,700&display=swap" rel = "stylesheet" />
2026-05-29 00:33:00 +03:00
2026-05-29 09:37:07 +03:00
@ vite ([ 'resources/css/app.css' , 'resources/js/app.js' ])
@ stack ( 'styles' )
</ head >
< body class = "h-full bg-[#0f0f13] text-slate-200 antialiased font-sans" >
2026-05-29 00:33:00 +03:00
2026-05-29 09:37:07 +03:00
<!-- Navigation -->
< nav class = "bg-[#16161d] border-b border-white/5 sticky top-0 z-50" >
< div class = "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8" >
< div class = "flex items-center justify-between h-16" >
<!-- Left : Logo + Nav Links -->
< div class = "flex items-center gap-8" >
< a href = "{{ route('home') }}" class = "text-xl font-bold text-purple-400 hover:text-purple-300 transition-colors" >
2026-05-31 14:19:47 +03:00
LoreKeepers
2026-05-29 09:37:07 +03:00
</ a >
< div class = "hidden md:flex items-center gap-6" >
< a href = "{{ route('games.index') }}" class = "text-sm text-slate-400 hover:text-slate-200 transition-colors" > Browse </ a >
< a href = "{{ route('games.top-rated') }}" class = "text-sm text-slate-400 hover:text-slate-200 transition-colors" > Top Rated </ a >
< a href = "{{ route('games.new-releases') }}" class = "text-sm text-slate-400 hover:text-slate-200 transition-colors" > New Releases </ a >
2026-05-30 11:23:24 +03:00
@ auth
< a href = "{{ route('activity.index') }}" class = "text-sm text-slate-400 hover:text-slate-200 transition-colors" > Activity </ a >
@ endauth
2026-05-29 00:33:00 +03:00
</ div >
2026-05-29 09:37:07 +03:00
</ div >
2026-05-29 00:33:00 +03:00
2026-05-30 02:50:34 +03:00
<!-- Center : Search with Autocomplete -->
< div class = "flex-1 max-w-md mx-8 hidden md:block" x - data = "searchWidget()" >
< form @ submit . prevent = "goToSearch()" class = "relative" >
< svg class = "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-500 pointer-events-none z-10" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
< path stroke - linecap = "round" stroke - linejoin = "round" stroke - width = "2" d = "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0" />
</ svg >
< input type = "text" x - model = "query" @ input . debounce . 300 ms = "fetchResults()"
@ focus = "if (results.length) open = true"
@ keydown . escape = "open = false; results = []"
@ keydown . arrow - down . prevent = "focusResult(activeIndex + 1)"
@ keydown . arrow - up . prevent = "focusResult(activeIndex - 1)"
@ keydown . enter . prevent = "activeIndex >= 0 && results[activeIndex] ? navigateToResult(results[activeIndex]) : goToSearch()"
placeholder = "Search games…" autocomplete = "off"
class = "w-full bg-[#0f0f13] border border-white/10 rounded-lg pl-10 pr-4 py-2 text-sm text-slate-200 placeholder-slate-500 focus:outline-none focus:border-purple-500 focus:ring-1 focus:ring-purple-500 transition" >
<!-- Autocomplete Dropdown -->
< div x - show = "open && results.length > 0" @ click . outside = "open = false"
x - transition : enter = "transition ease-out duration-100"
x - transition : enter - start = "opacity-0 -translate-y-1"
x - transition : enter - end = "opacity-100 translate-y-0"
class = "absolute top-full left-0 right-0 mt-1 bg-[#16161d] border border-white/10 rounded-lg shadow-xl overflow-hidden z-50"
style = "display:none;" >
< template x - for = "(result, i) in results" : key = "result.id" >
< button type = "button"
@ click = "navigateToResult(result)"
@ mouseenter = "activeIndex = i"
: class = "activeIndex === i ? 'bg-white/5' : ''"
class = "w-full flex items-center gap-3 px-3 py-2 text-left hover:bg-white/5 transition-colors" >
< template x - if = "result.cover_thumb" >
< img : src = "result.cover_thumb" alt = ""
class = "w-8 h-10 object-cover rounded flex-shrink-0 bg-[#0f0f13]" >
</ template >
< template x - if = "!result.cover_thumb" >
< div class = "w-8 h-10 flex-shrink-0 bg-[#0f0f13] rounded flex items-center justify-center" >
< svg class = "w-4 h-4 text-slate-600" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
< path stroke - linecap = "round" stroke - linejoin = "round" stroke - width = "1.5" d = "M15 5v2m0 4v2m0 4v2M5 5a2 2 0 00-2 2v3a2 2 0 110 4v3a2 2 0 002 2h14a2 2 0 002-2v-3a2 2 0 110-4V7a2 2 0 00-2-2H5z" />
</ svg >
</ div >
</ template >
< div class = "min-w-0" >
< div class = "text-sm text-slate-200 truncate" x - text = "result.title" ></ div >
< div class = "text-xs text-slate-500" x - text = "result.release_year ?? ''" ></ div >
</ div >
</ button >
</ template >
2026-05-29 09:37:07 +03:00
</ div >
</ form >
</ div >
<!-- Right : Auth -->
< div class = "flex items-center gap-3" >
@ auth
2026-05-30 11:23:24 +03:00
{{ -- Notification bell -- }}
@ php $unreadCount = auth () -> user () -> notifications () -> whereNull ( 'read_at' ) -> count (); @ endphp
< a href = "{{ route('notifications.index') }}" class = "relative text-slate-400 hover:text-slate-200 transition-colors" >
< svg class = "w-5 h-5" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
< path stroke - linecap = "round" stroke - linejoin = "round" stroke - width = "2"
d = "M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
</ svg >
@ if ( $unreadCount > 0 )
< span class = "absolute -top-1 -right-1 w-4 h-4 bg-purple-600 rounded-full text-[10px] font-bold text-white flex items-center justify-center" >
{{ $unreadCount > 9 ? '9+' : $unreadCount }}
</ span >
@ endif
</ a >
2026-05-29 09:37:07 +03:00
< div class = "relative" x - data = "{ open: false }" >
< button @ click = "open = !open" class = "flex items-center gap-2 text-sm text-slate-400 hover:text-slate-200 transition-colors" >
@ if ( auth () -> user () -> avatar )
< img src = "{{ auth()->user()->avatar }}" class = "w-8 h-8 rounded-full object-cover border border-white/10" alt = "" >
@ else
< div class = "w-8 h-8 rounded-full bg-purple-600 flex items-center justify-center text-xs font-bold text-white" >
{{ strtoupper ( substr ( auth () -> user () -> name , 0 , 1 )) }}
</ div >
@ endif
2026-05-30 23:47:32 +03:00
< span class = "hidden sm:block" > {{ auth () -> user () -> slug ?? auth () -> user () -> name }} </ span >
2026-05-29 09:37:07 +03:00
< svg class = "w-4 h-4" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
< path stroke - linecap = "round" stroke - linejoin = "round" stroke - width = "2" d = "M19 9l-7 7-7-7" />
</ svg >
</ button >
< div x - show = "open" @ click . outside = "open = false" x - transition
class = "absolute right-0 mt-2 w-48 bg-[#16161d] border border-white/10 rounded-lg shadow-xl overflow-hidden z-50" >
2026-05-30 23:47:32 +03:00
@ if ( auth () -> user () -> slug )
< a href = "{{ route('users.show', auth()->user()->slug) }}" class = "block px-4 py-2.5 text-sm text-slate-300 hover:bg-white/5 hover:text-white transition-colors" > Profile </ a >
< a href = "{{ route('users.library', auth()->user()->slug) }}" class = "block px-4 py-2.5 text-sm text-slate-300 hover:bg-white/5 hover:text-white transition-colors" > My Library </ a >
2026-05-30 02:50:34 +03:00
< a href = "{{ route('lists.index') }}" class = "block px-4 py-2.5 text-sm text-slate-300 hover:bg-white/5 hover:text-white transition-colors" > My Lists </ a >
2026-05-29 09:37:07 +03:00
@ endif
< a href = "{{ route('profile.edit') }}" class = "block px-4 py-2.5 text-sm text-slate-300 hover:bg-white/5 hover:text-white transition-colors" > Settings </ a >
< div class = "border-t border-white/5" ></ div >
< form method = "POST" action = "{{ route('logout') }}" >
@ csrf
< button type = "submit" class = "w-full text-left px-4 py-2.5 text-sm text-slate-400 hover:bg-white/5 hover:text-white transition-colors" >
Log Out
</ button >
</ form >
</ div >
</ div >
@ else
< a href = "{{ route('login') }}" class = "text-sm text-slate-400 hover:text-slate-200 transition-colors" > Log in </ a >
< a href = "{{ route('register') }}" class = "text-sm px-4 py-2 bg-purple-600 hover:bg-purple-700 text-white rounded-lg transition-colors font-medium" >
Sign up
</ a >
@ endauth
</ div >
</ div >
2026-05-29 00:33:00 +03:00
</ div >
2026-05-29 09:37:07 +03:00
</ nav >
<!-- Flash Messages -->
@ if ( session ( 'success' ))
< div class = "bg-green-900/50 border-b border-green-700/50 text-green-300 text-sm text-center py-2 px-4" >
{{ session ( 'success' ) }}
</ div >
@ endif
@ if ( session ( 'error' ))
< div class = "bg-red-900/50 border-b border-red-700/50 text-red-300 text-sm text-center py-2 px-4" >
{{ session ( 'error' ) }}
</ div >
@ endif
<!-- Page Content -->
< main >
@ yield ( 'content' )
</ main >
<!-- Footer -->
< footer class = "border-t border-white/5 mt-16 py-10" >
< div class = "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8" >
< div class = "flex flex-col md:flex-row items-center justify-between gap-4" >
< div class = "text-slate-500 text-sm" >
2026-05-31 14:19:47 +03:00
© {{ date ( 'Y' ) }} LoreKeepers . Track every game you play .
2026-05-29 09:37:07 +03:00
</ div >
< div class = "flex items-center gap-6 text-sm text-slate-500" >
< a href = "{{ route('games.index') }}" class = "hover:text-slate-300 transition-colors" > Browse </ a >
< a href = "{{ route('games.top-rated') }}" class = "hover:text-slate-300 transition-colors" > Top Rated </ a >
< a href = "{{ route('games.new-releases') }}" class = "hover:text-slate-300 transition-colors" > New Releases </ a >
</ div >
</ div >
</ div >
</ footer >
@ stack ( 'scripts' )
2026-05-30 02:50:34 +03:00
< script >
function searchWidget () {
return {
query : '' ,
results : [],
open : false ,
activeIndex : - 1 ,
async fetchResults () {
if ( this . query . length < 2 ) {
this . results = [];
this . open = false ;
return ;
}
const res = await fetch ( `/games/search?q=${encodeURIComponent(this.query)}` , {
headers : { 'Accept' : 'application/json' },
});
if ( ! res . ok ) return ;
const data = await res . json ();
this . results = data . slice ( 0 , 6 );
this . activeIndex = - 1 ;
this . open = this . results . length > 0 ;
},
focusResult ( i ) {
const max = this . results . length - 1 ;
this . activeIndex = Math . max ( 0 , Math . min ( i , max ));
},
navigateToResult ( result ) {
window . location . href = result . url ;
},
goToSearch () {
if ( this . query . trim ()) {
window . location . href = `/games?q=${encodeURIComponent(this.query.trim())}` ;
}
},
};
}
</ script >
2026-05-29 09:37:07 +03:00
</ body >
2026-05-29 00:33:00 +03:00
</ html >