mirror of
https://github.com/ceratic/MediaCollectorLibary.git
synced 2026-05-13 23:56:46 +02:00
299 lines
20 KiB
Twig
299 lines
20 KiB
Twig
{% extends "layouts/app.twig" %}
|
|
|
|
{% block content %}
|
|
<div class="min-h-screen bg-gray-50">
|
|
<!-- Header Section -->
|
|
<div class="bg-white shadow-sm border-b border-gray-200">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h1 class="text-3xl font-bold text-gray-900">Search</h1>
|
|
{% if search %}
|
|
<p class="mt-1 text-lg text-gray-600">Results for "{{ search }}"</p>
|
|
{% else %}
|
|
<p class="mt-1 text-lg text-gray-600">Discover your media collection</p>
|
|
{% endif %}
|
|
</div>
|
|
{% if search and totalResults > 0 %}
|
|
<div class="text-right">
|
|
<p class="text-sm text-gray-500">{{ totalResults }} results found</p>
|
|
<p class="text-xs text-gray-400">Page {{ page }} of {{ totalPages }}</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Search and Filters -->
|
|
<div class="bg-white shadow-sm border-b border-gray-200">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
|
<form method="GET" class="space-y-4" x-data="{ showAdvanced: false }">
|
|
<!-- Main Search Bar -->
|
|
<div class="flex gap-4">
|
|
<div class="flex-1 relative">
|
|
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
|
<svg class="h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<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 0z"/>
|
|
</svg>
|
|
</div>
|
|
<input
|
|
type="text"
|
|
name="q"
|
|
value="{{ search }}"
|
|
placeholder="Search movies, games, TV shows, music, and more..."
|
|
class="block w-full pl-10 pr-3 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-gray-900 placeholder-gray-500"
|
|
autofocus
|
|
>
|
|
</div>
|
|
<button type="submit" class="px-6 py-3 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors">
|
|
Search
|
|
</button>
|
|
<button type="button" @click="showAdvanced = !showAdvanced" class="px-4 py-3 border border-gray-300 text-gray-700 font-medium rounded-lg hover:bg-gray-50 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors">
|
|
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 100 4m0-4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 100 4m0-4v2m0-6V4"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Advanced Filters -->
|
|
<div x-show="showAdvanced" x-transition class="border-t border-gray-200 pt-4 space-y-4">
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<!-- Media Type Filter -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">Media Type</label>
|
|
<select name="type" class="block w-full border border-gray-300 rounded-md px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
|
<option value="all" {{ type == 'all' ? 'selected' : '' }}>All Types</option>
|
|
<option value="movies" {{ type == 'movies' ? 'selected' : '' }}>Movies</option>
|
|
<option value="games" {{ type == 'games' ? 'selected' : '' }}>Games</option>
|
|
<option value="tvshows" {{ type == 'tvshows' ? 'selected' : '' }}>TV Shows</option>
|
|
<option value="music" {{ type == 'music' ? 'selected' : '' }}>Music</option>
|
|
<option value="adult" {{ type == 'adult' ? 'selected' : '' }}>Adult Videos</option>
|
|
<option value="actors" {{ type == 'actors' ? 'selected' : '' }}>Performers</option>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Sort Options -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">Sort By</label>
|
|
<select name="sort" class="block w-full border border-gray-300 rounded-md px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
|
<option value="relevance" {{ sort == 'relevance' ? 'selected' : '' }}>Relevance</option>
|
|
<option value="title" {{ sort == 'title' ? 'selected' : '' }}>Title (A-Z)</option>
|
|
<option value="date" {{ sort == 'date' ? 'selected' : '' }}>Date Added</option>
|
|
<option value="rating" {{ sort == 'rating' ? 'selected' : '' }}>Rating</option>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Clear Filters -->
|
|
<div class="flex items-end">
|
|
<a href="{{ path_for('search.index') }}" class="w-full px-4 py-2 text-center border border-gray-300 text-gray-700 font-medium rounded-md hover:bg-gray-50 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors">
|
|
Clear Filters
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Results Section -->
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
{% if search %}
|
|
{% if hasResults %}
|
|
<!-- Results Grid -->
|
|
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 xl:grid-cols-6 gap-6">
|
|
{% for mediaType, items in results %}
|
|
{% for item in items %}
|
|
<div class="group relative bg-white rounded-lg shadow-sm hover:shadow-lg transition-shadow duration-200 overflow-hidden">
|
|
<!-- Media Poster/Image -->
|
|
|
|
|
|
|
|
|
|
<div class="aspect-[2/3] bg-gray-200 relative overflow-hidden">
|
|
{% if item.poster_url %}
|
|
<img src="{% if '/images/' in item.poster_url %}{{ item.poster_url }}{% else %}/images/{{ item.poster_url }}{% endif %}" alt="{{ item.title or item.name }}" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-200">
|
|
{% elseif item.cover_image %}
|
|
<img src="{% if '/images/' in item.cover_image %}/playnite/{{ item.cover_image }}{% else %}/images/playnite/{{ item.cover_image }}{% endif %}" alt="{{ item.title or item.name }}" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-200">
|
|
{% elseif item.image_url %}
|
|
<img src="{% if '/images/' in item.image_url %}/playnite/{{ item.image_url }}{% else %}/images/playnite/{{ item.image_url }}{% endif %}" alt="{{ item.title or item.name }}" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-200">
|
|
{% elseif item.thumbnail %}
|
|
<img src="{% if '/images/' in item.thumbnail %}{{ item.thumbnail }}{% else %}/images/{{ item.thumbnail }}{% endif %}" alt="{{ item.title or item.name }}" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-200">
|
|
{% else %}
|
|
<div class="w-full h-full bg-gradient-to-br from-gray-300 to-gray-400 flex items-center justify-center">
|
|
<svg class="h-12 w-12 text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
{% if item.type == 'movie' or item.type == 'tvshow' or item.type == 'adult' %}
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z"/>
|
|
{% elseif item.type == 'game' %}
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
|
|
{% elseif item.type == 'music' %}
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"/>
|
|
{% elseif item.type == 'actor' %}
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
|
|
{% endif %}
|
|
</svg>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Media Type Badge -->
|
|
<div class="absolute top-2 left-2">
|
|
<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium
|
|
{% if item.type == 'movie' %}bg-blue-100 text-blue-800
|
|
{% elseif item.type == 'game' %}bg-green-100 text-green-800
|
|
{% elseif item.type == 'tvshow' %}bg-purple-100 text-purple-800
|
|
{% elseif item.type == 'music' %}bg-yellow-100 text-yellow-800
|
|
{% elseif item.type == 'adult' %}bg-red-100 text-red-800
|
|
{% elseif item.type == 'actor' %}bg-pink-100 text-pink-800
|
|
{% endif %}">
|
|
{% if item.type == 'movie' %}Movie
|
|
{% elseif item.type == 'game' %}Game
|
|
{% elseif item.type == 'tvshow' %}TV Show
|
|
{% elseif item.type == 'music' %}Music
|
|
{% elseif item.type == 'adult' %}Adult
|
|
{% elseif item.type == 'actor' %}Actor
|
|
{% endif %}
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Hover Overlay -->
|
|
<div class="absolute inset-0 opacity-0 bg-black group-hover:opacity-50 transition-all duration-200 flex items-center justify-center">
|
|
<a href="
|
|
{% if item.type == 'movie' %}{{ path_for('movies.show', {'id': item.id}) }}
|
|
{% elseif item.type == 'game' %}{{ path_for('games.show', {'game_key': item.game_key}) }}
|
|
{% elseif item.type == 'tvshow' %}{{ path_for('tvshows.show', {'id': item.id}) }}
|
|
{% elseif item.type == 'music' %}{{ path_for('music.show', {'id': item.id}) }}
|
|
{% elseif item.type == 'adult' %}{{ path_for('adult.show', {'id': item.id}) }}
|
|
{% elseif item.type == 'actor' %}{{ path_for('actors.show', {'id': item.id}) }}
|
|
{% endif %}"
|
|
class="opacity-0 group-hover:opacity-100 bg-white text-gray-900 px-4 py-2 rounded-lg font-medium text-sm transition-all duration-200 hover:bg-gray-100">
|
|
View Details
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Content -->
|
|
<div class="p-4">
|
|
<h3 class="font-medium text-gray-900 text-sm leading-tight line-clamp-2 mb-1">
|
|
<a href="
|
|
{% if item.type == 'movie' %}{{ path_for('movies.show', {'id': item.id}) }}
|
|
{% elseif item.type == 'game' %}{{ path_for('games.show', {'game_key': item.game_key}) }}
|
|
{% elseif item.type == 'tvshow' %}{{ path_for('tvshows.show', {'id': item.id}) }}
|
|
{% elseif item.type == 'music' %}{{ path_for('music.show', {'id': item.id}) }}
|
|
{% elseif item.type == 'adult' %}{{ path_for('adult.show', {'id': item.id}) }}
|
|
{% elseif item.type == 'actor' %}{{ path_for('actors.show', {'id': item.id}) }}
|
|
{% endif %}"
|
|
class="hover:text-blue-600 transition-colors">
|
|
{{ item.title }}
|
|
</a>
|
|
</h3>
|
|
|
|
{% if item.source_name %}
|
|
<p class="text-xs text-gray-500 mb-2">{{ item.source_name }}</p>
|
|
{% endif %}
|
|
|
|
{% if item.artist %}
|
|
<p class="text-xs text-gray-600 mb-2">{{ item.artist }}</p>
|
|
{% endif %}
|
|
|
|
{% if item.release_date %}
|
|
<p class="text-xs text-gray-500">{{ item.release_date|date('Y') }}</p>
|
|
{% endif %}
|
|
|
|
{% if item.added_date %}
|
|
<p class="text-xs text-gray-400">Added {{ item.added_date|date('M j, Y') }}</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
{% if totalPages > 1 %}
|
|
<div class="mt-12 flex items-center justify-between">
|
|
<div class="text-sm text-gray-700">
|
|
Showing page {{ page }} of {{ totalPages }}
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
{% if page > 1 %}
|
|
<a href="?q={{ search|url_encode }}&type={{ type }}&sort={{ sort }}&page={{ page - 1 }}" class="px-3 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-md hover:bg-gray-50">
|
|
Previous
|
|
</a>
|
|
{% endif %}
|
|
|
|
{% set startPage = max(1, page - 2) %}
|
|
{% set endPage = min(totalPages, page + 2) %}
|
|
|
|
{% if startPage > 1 %}
|
|
<a href="?q={{ search|url_encode }}&type={{ type }}&sort={{ sort }}&page=1" class="px-3 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-md hover:bg-gray-50">1</a>
|
|
{% if startPage > 2 %}
|
|
<span class="px-2 py-2 text-sm text-gray-400">...</span>
|
|
{% endif %}
|
|
{% endif %}
|
|
|
|
{% for i in startPage..endPage %}
|
|
<a href="?q={{ search|url_encode }}&type={{ type }}&sort={{ sort }}&page={{ i }}" class="px-3 py-2 text-sm font-medium {{ i == page ? 'text-blue-600 bg-blue-50 border-blue-500' : 'text-gray-500 bg-white border-gray-300' }} border rounded-md hover:bg-gray-50">
|
|
{{ i }}
|
|
</a>
|
|
{% endfor %}
|
|
|
|
{% if endPage < totalPages %}
|
|
{% if endPage < totalPages - 1 %}
|
|
<span class="px-2 py-2 text-sm text-gray-400">...</span>
|
|
{% endif %}
|
|
<a href="?q={{ search|url_encode }}&type={{ type }}&sort={{ sort }}&page={{ totalPages }}" class="px-3 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-md hover:bg-gray-50">{{ totalPages }}</a>
|
|
{% endif %}
|
|
|
|
{% if page < totalPages %}
|
|
<a href="?q={{ search|url_encode }}&type={{ type }}&sort={{ sort }}&page={{ page + 1 }}" class="px-3 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-md hover:bg-gray-50">
|
|
Next
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% else %}
|
|
<!-- No Results -->
|
|
<div class="text-center py-16">
|
|
<div class="mx-auto w-24 h-24 bg-gray-100 rounded-full flex items-center justify-center mb-6">
|
|
<svg class="w-12 h-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<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 0z"/>
|
|
</svg>
|
|
</div>
|
|
<h3 class="text-xl font-medium text-gray-900 mb-2">No results found</h3>
|
|
<p class="text-gray-500 mb-6">Try adjusting your search terms or filters</p>
|
|
<div class="flex justify-center space-x-4">
|
|
<a href="{{ path_for('dashboard.index') }}" class="inline-flex items-center px-4 py-2 border border-gray-300 text-gray-700 font-medium rounded-lg hover:bg-gray-50 transition-colors">
|
|
Browse Library
|
|
</a>
|
|
<a href="{{ path_for('search.index') }}" class="inline-flex items-center px-4 py-2 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 transition-colors">
|
|
Clear Search
|
|
</a>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% else %}
|
|
<!-- Empty State -->
|
|
<div class="text-center py-16">
|
|
<div class="mx-auto w-24 h-24 bg-blue-100 rounded-full flex items-center justify-center mb-6">
|
|
<svg class="w-12 h-12 text-blue-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<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 0z"/>
|
|
</svg>
|
|
</div>
|
|
<h3 class="text-xl font-medium text-gray-900 mb-2">Search your media collection</h3>
|
|
<p class="text-gray-500">Find movies, games, TV shows, music, and more</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.line-clamp-2 {
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 2;
|
|
-webkit-box-orient: vertical;
|
|
overflow: hidden;
|
|
}
|
|
</style>
|
|
{% endblock %}
|