mirror of
https://github.com/ceratic/MediaCollectorLibary.git
synced 2026-05-13 23:56:46 +02:00
dont know ?
This commit is contained in:
280
resources/views/actor/edit.twig
Normal file
280
resources/views/actor/edit.twig
Normal file
@@ -0,0 +1,280 @@
|
||||
{% extends "layouts/app.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="p-6">
|
||||
<!-- Header -->
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-gray-900">Edit Actor</h1>
|
||||
<p class="text-gray-600 mt-1">Update actor information and metadata</p>
|
||||
</div>
|
||||
<a href="{{ path_for('actors.show', {'id': actor.id}) }}" class="bg-gray-500 text-white px-4 py-2 rounded-md hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2">
|
||||
Cancel
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if error %}
|
||||
<div class="bg-red-50 border border-red-200 rounded-md p-4 mb-6">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-red-800">Error</h3>
|
||||
<div class="mt-2 text-sm text-red-700">
|
||||
{{ error }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Edit Form -->
|
||||
<form method="POST" enctype="multipart/form-data" class="bg-white rounded-lg shadow-md border border-gray-200">
|
||||
<div class="px-6 py-4 border-b border-gray-200">
|
||||
<h2 class="text-lg font-medium text-gray-900">Basic Information</h2>
|
||||
</div>
|
||||
|
||||
<div class="p-6 space-y-6">
|
||||
<!-- Name -->
|
||||
<div>
|
||||
<label for="name" class="block text-sm font-medium text-gray-700">Name *</label>
|
||||
<input type="text" name="name" id="name" value="{{ actor.name }}" required
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
|
||||
<!-- Current Image -->
|
||||
{% if actor.thumbnail_path %}
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Current Image</label>
|
||||
<div class="mt-1 flex items-center space-x-4">
|
||||
<img src="{{ actor.thumbnail_path }}" alt="{{ actor.name }}" class="w-24 h-32 object-cover rounded border">
|
||||
<div class="text-sm text-gray-500">
|
||||
Current actor image. Upload a new image below to replace it.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Image Upload -->
|
||||
<div>
|
||||
<label for="thumbnail" class="block text-sm font-medium text-gray-700">Upload New Image</label>
|
||||
<input type="file" name="thumbnail" id="thumbnail" accept="image/*"
|
||||
class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100">
|
||||
<p class="mt-1 text-sm text-gray-500">Supported formats: JPEG, PNG, GIF, WebP. Maximum file size: 5MB.</p>
|
||||
</div>
|
||||
|
||||
<!-- Biography -->
|
||||
<div>
|
||||
<label for="biography" class="block text-sm font-medium text-gray-700">Biography</label>
|
||||
<textarea name="biography" id="biography" rows="4"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2"
|
||||
placeholder="Enter actor biography...">{{ metadata.biography ?? '' }}</textarea>
|
||||
</div>
|
||||
|
||||
<!-- Personal Information -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div>
|
||||
<label for="birth_date" class="block text-sm font-medium text-gray-700">Birth Date</label>
|
||||
<input type="date" name="birth_date" id="birth_date" value="{{ metadata.birth_date ?? '' }}"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
<div>
|
||||
<label for="death_date" class="block text-sm font-medium text-gray-700">Death Date</label>
|
||||
<input type="date" name="death_date" id="death_date" value="{{ metadata.death_date ?? '' }}"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
<div>
|
||||
<label for="gender" class="block text-sm font-medium text-gray-700">Gender</label>
|
||||
<select name="gender" id="gender"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
<option value="">Select Gender</option>
|
||||
<option value="FEMALE" {{ (metadata.gender ?? '') == 'FEMALE' ? 'selected' : '' }}>Female</option>
|
||||
<option value="MALE" {{ (metadata.gender ?? '') == 'MALE' ? 'selected' : '' }}>Male</option>
|
||||
<option value="TRANSGENDER_FEMALE" {{ (metadata.gender ?? '') == 'TRANSGENDER_FEMALE' ? 'selected' : '' }}>Transgender Female</option>
|
||||
<option value="TRANSGENDER_MALE" {{ (metadata.gender ?? '') == 'TRANSGENDER_MALE' ? 'selected' : '' }}>Transgender Male</option>
|
||||
<option value="INTERSEX" {{ (metadata.gender ?? '') == 'INTERSEX' ? 'selected' : '' }}>Intersex</option>
|
||||
<option value="NON_BINARY" {{ (metadata.gender ?? '') == 'NON_BINARY' ? 'selected' : '' }}>Non-binary</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="birth_place" class="block text-sm font-medium text-gray-700">Birth Place</label>
|
||||
<input type="text" name="birth_place" id="birth_place" value="{{ metadata.birth_place ?? '' }}"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
<div>
|
||||
<label for="nationality" class="block text-sm font-medium text-gray-700">Nationality</label>
|
||||
<input type="text" name="nationality" id="nationality" value="{{ metadata.nationality ?? '' }}"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
<div>
|
||||
<label for="ethnicity" class="block text-sm font-medium text-gray-700">Ethnicity</label>
|
||||
<input type="text" name="ethnicity" id="ethnicity" value="{{ metadata.ethnicity ?? '' }}"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Physical Attributes -->
|
||||
<div class="border-t border-gray-200 pt-6">
|
||||
<h3 class="text-lg font-medium text-gray-900 mb-4">Physical Attributes</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div>
|
||||
<label for="height" class="block text-sm font-medium text-gray-700">Height</label>
|
||||
<input type="text" name="height" id="height" value="{{ metadata.height ?? '' }}"
|
||||
placeholder="e.g., 5'6" or 168cm"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
<div>
|
||||
<label for="measurements" class="block text-sm font-medium text-gray-700">Measurements</label>
|
||||
<input type="text" name="measurements" id="measurements" value="{{ metadata.measurements ?? '' }}"
|
||||
placeholder="e.g., 34-24-34"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
<div>
|
||||
<label for="cup_size" class="block text-sm font-medium text-gray-700">Cup Size</label>
|
||||
<input type="text" name="cup_size" id="cup_size" value="{{ metadata.cup_size ?? '' }}"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
<div>
|
||||
<label for="ethnicity" class="block text-sm font-medium text-gray-700">Ethnicity</label>
|
||||
<input type="text" name="ethnicity" id="ethnicity" value="{{ metadata.ethnicity ?? '' }}"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
<div>
|
||||
<label for="hair_color" class="block text-sm font-medium text-gray-700">Hair Color</label>
|
||||
<input type="text" name="hair_color" id="hair_color" value="{{ metadata.hair_color ?? '' }}"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
<div>
|
||||
<label for="eye_color" class="block text-sm font-medium text-gray-700">Eye Color</label>
|
||||
<input type="text" name="eye_color" id="eye_color" value="{{ metadata.eye_color ?? '' }}"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Body Modifications -->
|
||||
<div class="border-t border-gray-200 pt-6">
|
||||
<h3 class="text-lg font-medium text-gray-900 mb-4">Body Modifications</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label for="piercings" class="block text-sm font-medium text-gray-700">Piercings</label>
|
||||
<input type="text" name="piercings" id="piercings" value="{{ metadata.piercings ?? '' }}"
|
||||
placeholder="e.g., navel, nipples"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
<div>
|
||||
<label for="tattoos" class="block text-sm font-medium text-gray-700">Tattoos</label>
|
||||
<input type="text" name="tattoos" id="tattoos" value="{{ metadata.tattoos ?? '' }}"
|
||||
placeholder="e.g., lower back, ankle"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Aliases -->
|
||||
<div class="border-t border-gray-200 pt-6">
|
||||
<div>
|
||||
<label for="aliases" class="block text-sm font-medium text-gray-700">Aliases</label>
|
||||
<input type="text" name="aliases" id="aliases" value="{{ (metadata.aliases ?? [])|join(', ') }}"
|
||||
placeholder="e.g., Stage Name, Other Names (comma-separated)"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
<p class="mt-1 text-sm text-gray-500">Separate multiple aliases with commas</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Social Media -->
|
||||
<div class="border-t border-gray-200 pt-6">
|
||||
<h3 class="text-lg font-medium text-gray-900 mb-4">Social Media</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label for="twitter" class="block text-sm font-medium text-gray-700">Twitter</label>
|
||||
<input type="url" name="twitter" id="twitter" value="{{ metadata.social_media.twitter ?? '' }}"
|
||||
placeholder="https://twitter.com/username"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
<div>
|
||||
<label for="instagram" class="block text-sm font-medium text-gray-700">Instagram</label>
|
||||
<input type="url" name="instagram" id="instagram" value="{{ metadata.social_media.instagram ?? '' }}"
|
||||
placeholder="https://instagram.com/username"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
<div>
|
||||
<label for="onlyfans" class="block text-sm font-medium text-gray-700">OnlyFans</label>
|
||||
<input type="url" name="onlyfans" id="onlyfans" value="{{ metadata.social_media.onlyfans ?? '' }}"
|
||||
placeholder="https://onlyfans.com/username"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
<div>
|
||||
<label for="website" class="block text-sm font-medium text-gray-700">Website</label>
|
||||
<input type="url" name="website" id="website" value="{{ metadata.social_media.website ?? '' }}"
|
||||
placeholder="https://example.com"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Adult-Specific Information -->
|
||||
<div class="border-t border-gray-200 pt-6">
|
||||
<h3 class="text-lg font-medium text-gray-900 mb-4">Adult Industry Information</h3>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
|
||||
<div>
|
||||
<label for="debut_year" class="block text-sm font-medium text-gray-700">Debut Year</label>
|
||||
<input type="number" name="debut_year" id="debut_year" value="{{ metadata.adult_specific.debut_year ?? '' }}"
|
||||
min="1900" max="{{ 'now'|date('Y') + 5 }}"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
<div>
|
||||
<label for="retirement_year" class="block text-sm font-medium text-gray-700">Retirement Year</label>
|
||||
<input type="number" name="retirement_year" id="retirement_year" value="{{ metadata.adult_specific.retirement_year ?? '' }}"
|
||||
min="1900" max="{{ 'now'|date('Y') + 10 }}"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<div class="flex items-center">
|
||||
<input type="checkbox" name="active" id="active" value="1" {{ (metadata.adult_specific.active ?? false) ? 'checked' : '' }}
|
||||
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
|
||||
<label for="active" class="ml-2 block text-sm text-gray-900">
|
||||
Currently Active in Adult Industry
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label for="adult_genres" class="block text-sm font-medium text-gray-700">Adult Genres</label>
|
||||
<input type="text" name="adult_genres" id="adult_genres" value="{{ (metadata.adult_specific.genres ?? [])|join(', ') }}"
|
||||
placeholder="e.g., MILF, Anal, POV (comma-separated)"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
<p class="mt-1 text-sm text-gray-500">Genres this performer specializes in</p>
|
||||
</div>
|
||||
<div>
|
||||
<label for="specialties" class="block text-sm font-medium text-gray-700">Specialties</label>
|
||||
<input type="text" name="specialties" id="specialties" value="{{ (metadata.adult_specific.specialties ?? [])|join(', ') }}"
|
||||
placeholder="e.g., Deep Throat, Squirt, Roleplay (comma-separated)"
|
||||
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm px-3 py-2">
|
||||
<p class="mt-1 text-sm text-gray-500">Specific skills or specialties</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Form Actions -->
|
||||
<div class="px-6 py-4 bg-gray-50 border-t border-gray-200 flex justify-end space-x-3">
|
||||
<a href="{{ path_for('actors.show', {'id': actor.id}) }}" class="bg-gray-500 text-white px-4 py-2 rounded-md hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2">
|
||||
Cancel
|
||||
</a>
|
||||
<button type="submit" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,68 +1,346 @@
|
||||
{% extends "layouts/app.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="px-4 py-3">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="h3 fw-bold text-dark mb-1">Performers</h1>
|
||||
<p class="text-muted mb-0">{{ actors|length }} performer{{ actors|length != 1 ? 's' : '' }}</p>
|
||||
<!-- Hero Section -->
|
||||
<div class="relative">
|
||||
<div class="h-48 md:h-64 relative overflow-hidden bg-gradient-to-br from-purple-900 via-blue-900 to-indigo-900">
|
||||
<div class="absolute inset-0 bg-gradient-to-r from-purple-900/90 via-blue-900/70 to-indigo-900/90"></div>
|
||||
|
||||
<!-- Hero Content -->
|
||||
<div class="absolute inset-0 flex items-center justify-center">
|
||||
<div class="text-center text-white">
|
||||
<h1 class="text-3xl md:text-5xl font-bold mb-2">Actors & Performers</h1>
|
||||
<p class="text-lg md:text-xl opacity-90 mb-4">{{ pagination.total_items }} performer{{ pagination.total_items != 1 ? 's' : '' }}</p>
|
||||
|
||||
<!-- Pagination in Hero -->
|
||||
{% if pagination.total_pages > 0 %}
|
||||
<div class="flex items-center justify-center space-x-2">
|
||||
<!-- Previous Button -->
|
||||
{% if pagination.has_prev %}
|
||||
<a href="{{ path_for('actors.index') }}?{% for key, value in app.request.query %}{{ key }}={{ value }}{% if not loop.last %}&{% endif %}{% endfor %}{% if app.request.query|length > 0 %}&{% endif %}page={{ pagination.prev_page }}"
|
||||
class="px-3 py-2 text-sm font-medium text-white bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg hover:bg-white/30 transition-colors flex items-center">
|
||||
<svg class="w-4 h-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
||||
</svg>
|
||||
Prev
|
||||
</a>
|
||||
{% else %}
|
||||
<span class="px-3 py-2 text-sm font-medium text-white/50 bg-white/10 backdrop-blur-sm border border-white/20 rounded-lg cursor-not-allowed flex items-center">
|
||||
<svg class="w-4 h-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
||||
</svg>
|
||||
Prev
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page Info -->
|
||||
<span class="px-4 py-2 text-sm font-medium text-white bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg">
|
||||
Page {{ pagination.current_page }} of {{ pagination.total_pages }}
|
||||
</span>
|
||||
|
||||
<!-- Next Button -->
|
||||
{% if pagination.has_next %}
|
||||
<a href="{{ path_for('actors.index') }}?{% for key, value in app.request.query %}{{ key }}={{ value }}{% if not loop.last %}&{% endif %}{% endfor %}{% if app.request.query|length > 0 %}&{% endif %}page={{ pagination.next_page }}"
|
||||
class="px-3 py-2 text-sm font-medium text-white bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg hover:bg-white/30 transition-colors flex items-center">
|
||||
Next
|
||||
<svg class="w-4 h-4 ml-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
|
||||
</svg>
|
||||
</a>
|
||||
{% else %}
|
||||
<span class="px-3 py-2 text-sm font-medium text-white/50 bg-white/10 backdrop-blur-sm border border-white/20 rounded-lg cursor-not-allowed flex items-center">
|
||||
Next
|
||||
<svg class="w-4 h-4 ml-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
|
||||
</svg>
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="items">
|
||||
{% if actors %}
|
||||
<div class="row g-3">
|
||||
{% for actor in actors %}
|
||||
</div>
|
||||
|
||||
<figure class="item" style="padding:0px">
|
||||
<a href="{{ path_for('actors.show', {'id': actor.id}) }}" class="text-decoration-none">
|
||||
<img src="{{ actor.thumbnail_path }}" />
|
||||
<figcaption>{{ actor.name }}</figcaption>
|
||||
</a>
|
||||
</figure>
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
div class="col-md-6 col-lg-4 col-xl-2">
|
||||
<div class="item h-100">
|
||||
<div class="item-body text-center">
|
||||
<a href="{{ path_for('actors.show', {'id': actor.id}) }}" class="text-decoration-none">
|
||||
{% if actor.thumbnail_path %}
|
||||
<img src="{{ actor.thumbnail_path }}" alt="{{ actor.name }}" class="rounded-circle mb-3" style="width: 80px; height: 80px; object-fit: cover;">
|
||||
{% else %}
|
||||
<div class="rounded-circle bg-light d-flex align-items-center justify-content-center mb-3 mx-auto" style="width: 80px; height: 80px;">
|
||||
<svg class="text-muted" width="40" height="40" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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"/>
|
||||
<!-- Main Content -->
|
||||
<div class="max-w-7xl mx-auto px-4 py-8">
|
||||
<!-- Search and Filters Bar -->
|
||||
<div class="bg-white rounded-xl shadow-lg p-6 mb-8">
|
||||
<form method="GET" class="space-y-4">
|
||||
<!-- Search Bar -->
|
||||
<div class="flex flex-col md:flex-row gap-4">
|
||||
<div class="flex-1">
|
||||
<label for="search" class="block text-sm font-medium text-gray-700 mb-1">Search Actors</label>
|
||||
<div class="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>
|
||||
{% endif %}
|
||||
<input type="text" name="search" id="search" value="{{ search }}" placeholder="Search by actor name..."
|
||||
class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-lg focus:ring-blue-500 focus:border-blue-500">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="item-title mb-2">{{ actor.name }}</h5>
|
||||
<p class="item-text small text-muted">
|
||||
{{ actor.total_media_count }} scene{{ actor.total_media_count != 1 ? 's' : '' }}
|
||||
</p>
|
||||
|
||||
{% if actor.latest_scene_date %}
|
||||
<small class="text-muted d-block">
|
||||
Latest: {{ actor.latest_scene_date|date('M j, Y') }}
|
||||
</small>
|
||||
{% endif %}
|
||||
</a>
|
||||
<!-- Sort Options -->
|
||||
<div class="md:w-48">
|
||||
<label for="sort" class="block text-sm font-medium text-gray-700 mb-1">Sort By</label>
|
||||
<select name="sort" id="sort" class="block w-full py-2 px-3 border border-gray-300 rounded-lg focus:ring-blue-500 focus:border-blue-500">
|
||||
{% for value, label in sort_options %}
|
||||
<option value="{{ value }}" {{ sort == value ? 'selected' : '' }}>{{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div
|
||||
-->
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Filter Checkboxes -->
|
||||
<div class="flex flex-wrap gap-6">
|
||||
<div class="flex items-center">
|
||||
<input type="checkbox" name="has_movies" value="1" id="has_movies" {{ filters.has_movies == '1' ? 'checked' : '' }}
|
||||
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
|
||||
<label for="has_movies" class="ml-2 text-sm text-gray-700 flex items-center">
|
||||
<svg class="w-4 h-4 mr-1 text-blue-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 4V2a1 1 0 011-1h8a1 1 0 011 1v2h4a1 1 0 010 2h-1v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6H3a1 1 0 010-2h4z"/>
|
||||
</svg>
|
||||
Has Movies
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<input type="checkbox" name="has_tv_shows" value="1" id="has_tv_shows" {{ filters.has_tv_shows == '1' ? 'checked' : '' }}
|
||||
class="h-4 w-4 text-green-600 focus:ring-green-500 border-gray-300 rounded">
|
||||
<label for="has_tv_shows" class="ml-2 text-sm text-gray-700 flex items-center">
|
||||
<svg class="w-4 h-4 mr-1 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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"/>
|
||||
</svg>
|
||||
Has TV Shows
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<input type="checkbox" name="has_adult_videos" value="1" id="has_adult_videos" {{ filters.has_adult_videos == '1' ? 'checked' : '' }}
|
||||
class="h-4 w-4 text-red-600 focus:ring-red-500 border-gray-300 rounded">
|
||||
<label for="has_adult_videos" class="ml-2 text-sm text-gray-700 flex items-center">
|
||||
<svg class="w-4 h-4 mr-1 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
|
||||
</svg>
|
||||
Has Adult Videos
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex gap-2">
|
||||
<button type="submit" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg font-medium transition-colors flex items-center">
|
||||
<svg class="w-4 h-4 mr-2" 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>
|
||||
Search & Filter
|
||||
</button>
|
||||
<a href="{{ path_for('actors.index') }}" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-lg font-medium transition-colors flex items-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
Clear Filters
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% if actors %}
|
||||
<!-- Stats Overview -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
|
||||
<div class="bg-white rounded-xl shadow-lg p-6 text-center">
|
||||
<div class="w-12 h-12 bg-purple-100 rounded-full flex items-center justify-center mx-auto mb-3">
|
||||
<svg class="text-purple-600" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="text-2xl font-bold text-gray-900 mb-1">{{ actors|length }}</div>
|
||||
<div class="text-gray-600">Total Performers</div>
|
||||
</div>
|
||||
|
||||
{% set totalMovies = 0 %}
|
||||
{% set totalShows = 0 %}
|
||||
{% set totalAdult = 0 %}
|
||||
{% for actor in actors %}
|
||||
{% set totalMovies = totalMovies + actor.movie_count %}
|
||||
{% set totalShows = totalShows + actor.tv_show_count %}
|
||||
{% set totalAdult = totalAdult + actor.adult_video_count %}
|
||||
{% endfor %}
|
||||
|
||||
<div class="bg-white rounded-xl shadow-lg p-6 text-center">
|
||||
<div class="w-12 h-12 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-3">
|
||||
<svg class="text-blue-600" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 4V2a1 1 0 011-1h8a1 1 0 011 1v2h4a1 1 0 010 2h-1v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6H3a1 1 0 010-2h4z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="text-2xl font-bold text-gray-900 mb-1">{{ totalMovies }}</div>
|
||||
<div class="text-gray-600">Movies</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-xl shadow-lg p-6 text-center">
|
||||
<div class="w-12 h-12 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-3">
|
||||
<svg class="text-green-600" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="text-2xl font-bold text-gray-900 mb-1">{{ totalShows }}</div>
|
||||
<div class="text-gray-600">TV Shows</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-xl shadow-lg p-6 text-center">
|
||||
<div class="w-12 h-12 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-3">
|
||||
<svg class="text-red-600" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="text-2xl font-bold text-gray-900 mb-1">{{ totalAdult }}</div>
|
||||
<div class="text-gray-600">Adult Videos</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actors Grid -->
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8 gap-6">
|
||||
{% for actor in actors %}
|
||||
<a href="{{ path_for('actors.show', {'id': actor.id}) }}" class="group">
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-xl transition-all duration-300 hover:scale-105">
|
||||
<!-- Actor Avatar -->
|
||||
<div class="aspect-square bg-gray-200">
|
||||
{% if actor.thumbnail_path %}
|
||||
<img src="{% if '/images/' in actor.thumbnail_path %}{{ actor.thumbnail_path }}{% else %}/images/{{ actor.thumbnail_path }}{% endif %}" alt="{{ actor.name }}" class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-300">
|
||||
{% else %}
|
||||
<div class="w-full h-full bg-gradient-to-br from-blue-400 to-purple-500 flex items-center justify-center">
|
||||
<span class="text-2xl md:text-3xl font-bold text-white">{{ actor.name|first|upper }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Actor Info -->
|
||||
<div class="p-4">
|
||||
<h3 class="font-semibold text-gray-900 text-sm leading-tight mb-2 group-hover:text-blue-600 transition-colors line-clamp-2">{{ actor.name }}</h3>
|
||||
|
||||
<!-- Media Counts -->
|
||||
<div class="space-y-1">
|
||||
{% if actor.movie_count > 0 %}
|
||||
<div class="flex items-center text-xs text-gray-600">
|
||||
<svg class="w-3 h-3 mr-1 text-blue-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 4V2a1 1 0 011-1h8a1 1 0 011 1v2h4a1 1 0 010 2h-1v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6H3a1 1 0 010-2h4z"/>
|
||||
</svg>
|
||||
{{ actor.movie_count }} Movie{{ actor.movie_count != 1 ? 's' : '' }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if actor.tv_show_count > 0 %}
|
||||
<div class="flex items-center text-xs text-gray-600">
|
||||
<svg class="w-3 h-3 mr-1 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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"/>
|
||||
</svg>
|
||||
{{ actor.tv_show_count }} Show{{ actor.tv_show_count != 1 ? 's' : '' }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if actor.adult_video_count > 0 %}
|
||||
<div class="flex items-center text-xs text-gray-600">
|
||||
<svg class="w-3 h-3 mr-1 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
|
||||
</svg>
|
||||
{{ actor.adult_video_count }} Adult
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
{% if pagination.total_pages > 1 %}
|
||||
<div class="mt-12 flex items-center justify-between">
|
||||
<div class="text-sm text-gray-700">
|
||||
Showing {{ (pagination.current_page - 1) * pagination.per_page + 1 }} to {{ min(pagination.current_page * pagination.per_page, pagination.total_items) }} of {{ pagination.total_items }} performers
|
||||
</div>
|
||||
|
||||
<div class="flex items-center space-x-2">
|
||||
<!-- Previous Button -->
|
||||
{% if pagination.has_prev %}
|
||||
<a href="{{ path_for('actors.index') }}?{% for key, value in app.request.query %}{{ key }}={{ value }}{% if not loop.last %}&{% endif %}{% endfor %}{% if app.request.query|length > 0 %}&{% endif %}page={{ pagination.prev_page }}"
|
||||
class="px-3 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 hover:text-gray-700 transition-colors flex items-center">
|
||||
<svg class="w-4 h-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
||||
</svg>
|
||||
Previous
|
||||
</a>
|
||||
{% else %}
|
||||
<span class="px-3 py-2 text-sm font-medium text-gray-300 bg-gray-100 border border-gray-200 rounded-lg cursor-not-allowed flex items-center">
|
||||
<svg class="w-4 h-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
||||
</svg>
|
||||
Previous
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page Numbers -->
|
||||
{% set start_page = max(1, pagination.current_page - 2) %}
|
||||
{% set end_page = min(pagination.total_pages, pagination.current_page + 2) %}
|
||||
|
||||
{% if start_page > 1 %}
|
||||
<a href="{{ path_for('actors.index') }}?{% for key, value in app.request.query %}{{ key }}={{ value }}{% if not loop.last %}&{% endif %}{% endfor %}{% if app.request.query|length > 0 %}&{% endif %}page=1"
|
||||
class="px-3 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 hover:text-gray-700 transition-colors">1</a>
|
||||
{% if start_page > 2 %}
|
||||
<span class="px-2 py-2 text-sm font-medium text-gray-500">...</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% for page_num in start_page..end_page %}
|
||||
{% if page_num == pagination.current_page %}
|
||||
<span class="px-3 py-2 text-sm font-medium text-white bg-blue-600 border border-blue-600 rounded-lg">{{ page_num }}</span>
|
||||
{% else %}
|
||||
<a href="{{ path_for('actors.index') }}?{% for key, value in app.request.query %}{{ key }}={{ value }}{% if not loop.last %}&{% endif %}{% endfor %}{% if app.request.query|length > 0 %}&{% endif %}page={{ page_num }}"
|
||||
class="px-3 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 hover:text-gray-700 transition-colors">{{ page_num }}</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if end_page < pagination.total_pages %}
|
||||
{% if end_page < pagination.total_pages - 1 %}
|
||||
<span class="px-2 py-2 text-sm font-medium text-gray-500">...</span>
|
||||
{% endif %}
|
||||
<a href="{{ path_for('actors.index') }}?{% for key, value in app.request.query %}{{ key }}={{ value }}{% if not loop.last %}&{% endif %}{% endfor %}{% if app.request.query|length > 0 %}&{% endif %}page={{ pagination.total_pages }}"
|
||||
class="px-3 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 hover:text-gray-700 transition-colors">{{ pagination.total_pages }}</a>
|
||||
{% endif %}
|
||||
|
||||
<!-- Next Button -->
|
||||
{% if pagination.has_next %}
|
||||
<a href="{{ path_for('actors.index') }}?{% for key, value in app.request.query %}{{ key }}={{ value }}{% if not loop.last %}&{% endif %}{% endfor %}{% if app.request.query|length > 0 %}&{% endif %}page={{ pagination.next_page }}"
|
||||
class="px-3 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 hover:text-gray-700 transition-colors flex items-center">
|
||||
Next
|
||||
<svg class="w-4 h-4 ml-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
|
||||
</svg>
|
||||
</a>
|
||||
{% else %}
|
||||
<span class="px-3 py-2 text-sm font-medium text-gray-300 bg-gray-100 border border-gray-200 rounded-lg cursor-not-allowed flex items-center">
|
||||
Next
|
||||
<svg class="w-4 h-4 ml-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
|
||||
</svg>
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<svg class="text-muted mb-3" width="64" height="64" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"/>
|
||||
</svg>
|
||||
<h5 class="text-muted">No performers found</h5>
|
||||
<p class="text-muted">Performers will appear here once you sync content from your adult video sources.</p>
|
||||
</div>
|
||||
<!-- Empty State -->
|
||||
<div class="text-center py-16">
|
||||
<div class="w-24 h-24 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||
<svg class="text-gray-400 w-12 h-12" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">No Performers Found</h3>
|
||||
<p class="text-gray-600 max-w-md mx-auto">Performers will appear here once you sync content from your media sources. Import movies, TV shows, or adult videos to start building your actor database.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,113 +1,280 @@
|
||||
{% extends "layouts/app.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="px-4 py-3">
|
||||
<!-- Back button -->
|
||||
<div class="mb-4">
|
||||
<a href="{{ path_for('actors.index') }}" class="btn btn-outline-secondary btn-sm">
|
||||
<svg class="me-2" width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
||||
{% block sidebar %}
|
||||
{% if actor.metadata %}
|
||||
{% set metadata = actor.metadata|json_decode %}
|
||||
<div class="space-y-6">
|
||||
<!-- Personal Information -->
|
||||
{% if metadata.biography or metadata.birth_date or metadata.birth_place or metadata.nationality %}
|
||||
<div class="bg-white rounded-xl shadow-lg p-6">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-3 flex items-center">
|
||||
<svg class="mr-2 text-blue-600" width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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"/>
|
||||
</svg>
|
||||
Back to Performers
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="row g-0">
|
||||
<!-- Actor image -->
|
||||
<div class="col-md-4">
|
||||
<div class="card-body">
|
||||
<div class="text-center">
|
||||
{% if actor.thumbnail_path %}
|
||||
<img src="{{ actor.thumbnail_path }}" alt="{{ actor.name }}" class="rounded-circle mb-3" style="width: 150px; height: 150px; object-fit: cover;">
|
||||
{% else %}
|
||||
<div class="rounded-circle bg-light d-flex align-items-center justify-content-center mb-3 mx-auto" style="width: 150px; height: 150px;">
|
||||
<svg class="text-muted" width="75" height="75" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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"/>
|
||||
</svg>
|
||||
</div>
|
||||
{% endif %}
|
||||
<h1 class="h3 fw-bold text-dark mb-2">{{ actor.name }}</h1>
|
||||
<p class="text-muted">{{ actor.scene_count }} scene{{ actor.scene_count != 1 ? 's' : '' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
Personal Information
|
||||
</h3>
|
||||
<div class="space-y-3">
|
||||
{% if metadata.birth_date %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Birth Date</span>
|
||||
<span class="text-sm font-medium">{{ metadata.birth_date }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.birth_place %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Birth Place</span>
|
||||
<span class="text-sm font-medium">{{ metadata.birth_place }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.nationality %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Nationality</span>
|
||||
<span class="text-sm font-medium">{{ metadata.nationality }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.death_date %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Death Date</span>
|
||||
<span class="text-sm font-medium">{{ metadata.death_date }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Actor details and scenes -->
|
||||
<div class="col-md-8">
|
||||
<div class="card-body">
|
||||
<!-- Actor stats -->
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex align-items-center">
|
||||
<svg class="me-2 text-primary" width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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"/>
|
||||
</svg>
|
||||
<div>
|
||||
<div class="fw-semibold">{{ actor.scene_count }}</div>
|
||||
<small class="text-muted">Total Scenes</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Physical Attributes -->
|
||||
{% if metadata.gender or metadata.height or metadata.weight or metadata.hair_color or metadata.eye_color %}
|
||||
<div class="bg-white rounded-xl shadow-lg p-6">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-3 flex items-center">
|
||||
<svg class="mr-2 text-green-600" width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
|
||||
</svg>
|
||||
Physical Attributes
|
||||
</h3>
|
||||
<div class="space-y-3">
|
||||
{% if metadata.gender %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Gender</span>
|
||||
<span class="text-sm font-medium">{{ metadata.gender }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.height %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Height</span>
|
||||
<span class="text-sm font-medium">{{ metadata.height }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.weight %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Weight</span>
|
||||
<span class="text-sm font-medium">{{ metadata.weight }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.hair_color %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Hair Color</span>
|
||||
<span class="text-sm font-medium">{{ metadata.hair_color }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.eye_color %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Eye Color</span>
|
||||
<span class="text-sm font-medium">{{ metadata.eye_color }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.ethnicity %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Ethnicity</span>
|
||||
<span class="text-sm font-medium">{{ metadata.ethnicity }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if actor.scene_count > 0 %}
|
||||
<div class="col-sm-6">
|
||||
<div class="d-flex align-items-center">
|
||||
<svg class="me-2 text-success" width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
<div>
|
||||
<div class="fw-semibold">{{ actor.latest_scene_date|date('M j, Y') }}</div>
|
||||
<small class="text-muted">Latest Scene</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<!-- Adult-Specific Information -->
|
||||
{% if metadata.measurements or metadata.cup_size or metadata.fake_tits or metadata.penis_length or metadata.circumcised %}
|
||||
<div class="bg-white rounded-xl shadow-lg p-6">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-3 flex items-center">
|
||||
<svg class="mr-2 text-red-600" width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/>
|
||||
</svg>
|
||||
Adult Attributes
|
||||
</h3>
|
||||
<div class="space-y-3">
|
||||
{% if metadata.measurements %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Measurements</span>
|
||||
<span class="text-sm font-medium">{{ metadata.measurements }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.cup_size %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Cup Size</span>
|
||||
<span class="text-sm font-medium">{{ metadata.cup_size }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.fake_tits %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Fake Tits</span>
|
||||
<span class="text-sm font-medium">{{ metadata.fake_tits }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.penis_length %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Penis Length</span>
|
||||
<span class="text-sm font-medium">{{ metadata.penis_length }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.circumcised %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Circumcised</span>
|
||||
<span class="text-sm font-medium">{{ metadata.circumcised }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Scenes by this actor -->
|
||||
{% if scenes %}
|
||||
<div>
|
||||
<h3 class="h5 fw-semibold text-dark mb-3">Scenes featuring {{ actor.name }}</h3>
|
||||
<div class="row g-3">
|
||||
{% for scene in scenes %}
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100">
|
||||
<div style="background-color: #f8f9fa; height: 150px; overflow: hidden;">
|
||||
{% if scene.poster_url %}
|
||||
<img src="{{ scene.poster_url }}" alt="{{ scene.title }}" class="w-100 h-100" style="background-size: cover;">
|
||||
{% else %}
|
||||
<div class="w-100 h-100 d-flex align-items-center justify-content-center">
|
||||
<svg class="text-muted" width="48" height="48" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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"/>
|
||||
</svg>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6 class="card-title mb-1">
|
||||
<a href="{{ path_for('adult.show', {'id': scene.id}) }}" class="text-decoration-none">{{ scene.title }}</a>
|
||||
</h6>
|
||||
<p class="card-text small text-muted">
|
||||
{{ scene.release_date|date('M j, Y') }}
|
||||
{% if scene.runtime_minutes %}
|
||||
• {{ (scene.runtime_minutes / 60)|round(1) }}h {{ scene.runtime_minutes % 60 }}m
|
||||
{% endif %}
|
||||
</p>
|
||||
<small class="text-muted">{{ scene.source_name }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<!-- Career Information -->
|
||||
{% if metadata.career_length or metadata.scene_count %}
|
||||
<div class="bg-white rounded-xl shadow-lg p-6">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-3 flex items-center">
|
||||
<svg class="mr-2 text-purple-600" width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 13.255A23.931 23.931 0 0112 15c-3.183 0-6.22-.62-9-1.745M16 6V4a2 2 0 00-2-2h-4a2 2 0 00-2 2v2m8 0V8a2 2 0 01-2 2H8a2 2 0 01-2-2V6m8 0H8"/>
|
||||
</svg>
|
||||
Career Information
|
||||
</h3>
|
||||
<div class="space-y-3">
|
||||
{% if metadata.career_length %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Career Length</span>
|
||||
<span class="text-sm font-medium">{{ metadata.career_length }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.scene_count %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Scene Count</span>
|
||||
<span class="text-sm font-medium">{{ metadata.scene_count }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.adult_specific.debut_year %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Debut Year</span>
|
||||
<span class="text-sm font-medium">{{ metadata.adult_specific.debut_year }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.adult_specific.retirement_year %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Retirement Year</span>
|
||||
<span class="text-sm font-medium">{{ metadata.adult_specific.retirement_year }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.adult_specific.active is defined %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm text-gray-600">Active</span>
|
||||
<span class="text-sm font-medium">{{ metadata.adult_specific.active ? 'Yes' : 'No' }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Body Modifications -->
|
||||
{% if metadata.tattoos or metadata.piercings %}
|
||||
<div class="bg-white rounded-xl shadow-lg p-6">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-3 flex items-center">
|
||||
<svg class="mr-2 text-indigo-600" width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zM21 5a2 2 0 00-2-2h-4a2 2 0 00-2 2v12a4 4 0 004 4h4a2 2 0 002-2V5z"/>
|
||||
</svg>
|
||||
Body Modifications
|
||||
</h3>
|
||||
<div class="space-y-3">
|
||||
{% if metadata.tattoos %}
|
||||
<div>
|
||||
<p class="text-sm text-gray-600 mb-1">Tattoos</p>
|
||||
<p class="text-sm font-medium">{{ metadata.tattoos }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if metadata.piercings %}
|
||||
<div>
|
||||
<p class="text-sm text-gray-600 mb-1">Piercings</p>
|
||||
<p class="text-sm font-medium">{{ metadata.piercings }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Hero Section -->
|
||||
<div class="relative">
|
||||
<div class="h-64 md:h-80 relative overflow-hidden bg-gradient-to-br from-purple-900 via-blue-900 to-indigo-900">
|
||||
<div class="absolute inset-0 bg-gradient-to-r from-purple-900/90 via-blue-900/70 to-indigo-900/90"></div>
|
||||
|
||||
<!-- Action buttons -->
|
||||
<div class="absolute top-4 left-4 right-4 z-10 flex justify-between">
|
||||
<a href="{{ path_for('actors.index') }}" class="inline-flex items-center text-white hover:text-gray-300 transition-colors bg-black/20 backdrop-blur-sm rounded-full px-4 py-2">
|
||||
<svg class="mr-2" width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
||||
</svg>
|
||||
Back to Performers
|
||||
</a>
|
||||
|
||||
<a href="{{ path_for('actors.edit', {'id': actor.id}) }}" class="inline-flex items-center text-white hover:text-gray-300 transition-colors bg-black/20 backdrop-blur-sm rounded-full px-4 py-2">
|
||||
<svg class="mr-2" width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
|
||||
</svg>
|
||||
Edit
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Hero Content -->
|
||||
<div class="absolute inset-0 flex items-center justify-center">
|
||||
<div class="text-center text-white">
|
||||
<!-- Actor Avatar -->
|
||||
<div class="w-32 h-32 md:w-40 md:h-40 bg-white rounded-full overflow-hidden mb-4 mx-auto shadow-2xl">
|
||||
{% if actor.thumbnail_path %}
|
||||
<img src="{% if '/images/' in actor.thumbnail_path %}{{ actor.thumbnail_path }}{% else %}/images/{{ actor.thumbnail_path }}{% endif %}" alt="{{ actor.name }}" class="w-full h-full object-cover">
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<svg class="text-muted mb-3" width="64" height="64" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<div class="w-full h-full bg-gradient-to-br from-blue-400 to-purple-500 flex items-center justify-center">
|
||||
<span class="text-4xl md:text-5xl font-bold text-white">{{ actor.name|first|upper }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Actor Name -->
|
||||
<h1 class="text-3xl md:text-5xl font-bold mb-2">{{ actor.name }}</h1>
|
||||
|
||||
<!-- Quick Stats -->
|
||||
<div class="flex flex-wrap justify-center gap-6 text-sm">
|
||||
{% if actor.movie_count > 0 %}
|
||||
<div class="flex items-center">
|
||||
<svg class="mr-2" width="18" height="18" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 4V2a1 1 0 011-1h8a1 1 0 011 1v2h4a1 1 0 010 2h-1v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6H3a1 1 0 010-2h4z"/>
|
||||
</svg>
|
||||
<span class="font-medium">{{ actor.movie_count }} Movie{{ actor.movie_count != 1 ? 's' : '' }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if actor.tv_show_count > 0 %}
|
||||
<div class="flex items-center">
|
||||
<svg class="mr-2" width="18" height="18" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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"/>
|
||||
</svg>
|
||||
<h5 class="text-muted">No scenes found</h5>
|
||||
<p class="text-muted">This performer hasn't appeared in any scenes yet.</p>
|
||||
<span class="font-medium">{{ actor.tv_show_count }} TV Show{{ actor.tv_show_count != 1 ? 's' : '' }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if actor.adult_video_count > 0 %}
|
||||
<div class="flex items-center">
|
||||
<svg class="mr-2" width="18" height="18" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
|
||||
</svg>
|
||||
<span class="font-medium">{{ actor.adult_video_count }} Adult Video{{ actor.adult_video_count != 1 ? 's' : '' }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -115,4 +282,171 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="max-w-7xl mx-auto px-4 py-8">
|
||||
<!-- Detailed Stats -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
||||
{% if actor.movie_count > 0 %}
|
||||
<div class="bg-white rounded-xl shadow-lg p-6 text-center">
|
||||
<div class="w-12 h-12 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-3">
|
||||
<svg class="text-blue-600" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 4V2a1 1 0 011-1h8a1 1 0 011 1v2h4a1 1 0 010 2h-1v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6H3a1 1 0 010-2h4z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="text-2xl font-bold text-gray-900 mb-1">{{ actor.movie_count }}</div>
|
||||
<div class="text-gray-600">Movies</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if actor.tv_show_count > 0 %}
|
||||
<div class="bg-white rounded-xl shadow-lg p-6 text-center">
|
||||
<div class="w-12 h-12 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-3">
|
||||
<svg class="text-green-600" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="text-2xl font-bold text-gray-900 mb-1">{{ actor.tv_show_count }}</div>
|
||||
<div class="text-gray-600">TV Shows</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if actor.adult_video_count > 0 %}
|
||||
<div class="bg-white rounded-xl shadow-lg p-6 text-center">
|
||||
<div class="w-12 h-12 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-3">
|
||||
<svg class="text-red-600" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="text-2xl font-bold text-gray-900 mb-1">{{ actor.adult_video_count }}</div>
|
||||
<div class="text-gray-600">Adult Videos</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Movies Section -->
|
||||
{% if movies %}
|
||||
<div class="mb-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-6 flex items-center">
|
||||
<svg class="mr-3 text-blue-600" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 4V2a1 1 0 011-1h8a1 1 0 011 1v2h4a1 1 0 010 2h-1v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6H3a1 1 0 010-2h4z"/>
|
||||
</svg>
|
||||
Movies ({{ movies|length }})
|
||||
</h2>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-4">
|
||||
{% for movie in movies %}
|
||||
<a href="{{ path_for('movies.show', {'id': movie.id}) }}" class="group">
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-xl transition-shadow">
|
||||
<div class="aspect-[2/3] bg-gray-200">
|
||||
{% if movie.poster_url %}
|
||||
<img src="/images/{{ movie.poster_url }}" alt="{{ movie.title }}" class="w-full h-full object-cover group-hover:scale-105 transition-transform">
|
||||
{% else %}
|
||||
<div class="w-full h-full flex items-center justify-center bg-gradient-to-br from-gray-300 to-gray-400">
|
||||
<svg class="text-gray-500 w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 4V2a1 1 0 011-1h8a1 1 0 011 1v2h4a1 1 0 010 2h-1v14a2 2 0 01-2 2H6a2 2 0 01-2-2V6H3a1 1 0 010-2h4z"/>
|
||||
</svg>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="p-3">
|
||||
<h3 class="font-medium text-gray-900 text-sm leading-tight mb-1 group-hover:text-blue-600 transition-colors">{{ movie.title }}</h3>
|
||||
{% if movie.release_date %}
|
||||
<p class="text-xs text-gray-600">{{ movie.release_date|date('Y') }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- TV Shows Section -->
|
||||
{% if tv_shows %}
|
||||
<div class="mb-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-6 flex items-center">
|
||||
<svg class="mr-3 text-green-600" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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"/>
|
||||
</svg>
|
||||
TV Shows ({{ tv_shows|length }})
|
||||
</h2>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-4">
|
||||
{% for show in tv_shows %}
|
||||
<a href="{{ path_for('tvshows.show', {'id': show.id}) }}" class="group">
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-xl transition-shadow">
|
||||
<div class="aspect-[2/3] bg-gray-200">
|
||||
{% if show.poster_url %}
|
||||
<img src="/images/{{ show.poster_url }}" alt="{{ show.title }}" class="w-full h-full object-cover group-hover:scale-105 transition-transform">
|
||||
{% else %}
|
||||
<div class="w-full h-full flex items-center justify-center bg-gradient-to-br from-gray-300 to-gray-400">
|
||||
<svg class="text-gray-500 w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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"/>
|
||||
</svg>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="p-3">
|
||||
<h3 class="font-medium text-gray-900 text-sm leading-tight mb-1 group-hover:text-green-600 transition-colors">{{ show.title }}</h3>
|
||||
{% if show.first_air_date %}
|
||||
<p class="text-xs text-gray-600">{{ show.first_air_date|date('Y') }}{% if show.status == 'Ended' and show.last_air_date %} - {{ show.last_air_date|date('Y') }}{% endif %}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Adult Videos Section -->
|
||||
{% if scenes %}
|
||||
<div class="mb-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-6 flex items-center">
|
||||
<svg class="mr-3 text-red-600" width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
|
||||
</svg>
|
||||
Adult Videos ({{ scenes|length }})
|
||||
</h2>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-4">
|
||||
{% for scene in scenes %}
|
||||
<a href="{{ path_for('adult.show', {'id': scene.id}) }}" class="group">
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-xl transition-shadow">
|
||||
<div class="aspect-[2/3] bg-gray-200">
|
||||
{% if scene.poster_url %}
|
||||
<img src="/images/{{ scene.poster_url }}" alt="{{ scene.title }}" class="w-full h-full object-cover group-hover:scale-105 transition-transform">
|
||||
{% else %}
|
||||
<div class="w-full h-full flex items-center justify-center bg-gradient-to-br from-gray-300 to-gray-400">
|
||||
<svg class="text-gray-500 w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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"/>
|
||||
</svg>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="p-3">
|
||||
<h3 class="font-medium text-gray-900 text-sm leading-tight mb-1 group-hover:text-red-600 transition-colors">{{ scene.title }}</h3>
|
||||
{% if scene.release_date %}
|
||||
<p class="text-xs text-gray-600">{{ scene.release_date|date('M j, Y') }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- No Content Message -->
|
||||
{% if not movies and not tv_shows and not scenes %}
|
||||
<div class="text-center py-16">
|
||||
<div class="w-24 h-24 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||
<svg class="text-gray-400 w-12 h-12" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">No Media Found</h3>
|
||||
<p class="text-gray-600">This performer hasn't appeared in any movies, TV shows, or adult videos yet.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user