Files
thrillwiki_django_no_react/templates/cotton/park_card.html
pac7 25e6fdb496 Standardize park and ride cards using Django Cotton components
Introduces reusable Django Cotton components for park and ride cards, standardizing their presentation and enforcing the use of the django-cotton templating system. Updates static CSS for new color variables and gradient stops.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 0bdea3fb-49ea-4863-b501-fa6f5af0cbf0
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
2025-09-22 03:21:14 +00:00

190 lines
12 KiB
HTML

{% comment %}
Park Card Component - Django Cotton Version
A reusable park card component that supports both list and grid view modes.
Includes status badges, operator information, description, and ride/coaster statistics.
Usage Examples:
List View:
<c-park_card
park=park
view_mode="list"
/>
Grid View:
<c-park_card
park=park
view_mode="grid"
/>
With custom CSS classes:
<c-park_card
park=park
view_mode="grid"
class="custom-class"
/>
Parameters:
- park: Park object (required)
- view_mode: "list" or "grid" (default: "grid")
- class: Additional CSS classes (optional)
Features:
- Responsive design with hover effects
- Status badge with proper color coding
- Operator information display
- Description with automatic truncation (30 words for list, 15 for grid)
- Ride and coaster count statistics with icons
- Gradient effects and modern styling
- Links to park detail pages
{% endcomment %}
<c-vars
park=""
view_mode="grid"
class=""
/>
{% if park %}
{% if view_mode == 'list' %}
{# Enhanced List View Item #}
<article class="group bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm border border-gray-200/50 dark:border-gray-700/50 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 transform hover:scale-[1.02] overflow-hidden {{ class }}">
<div class="p-6">
<div class="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-6">
{# Main Content Section #}
<div class="flex-1 min-w-0">
<div class="flex items-start justify-between mb-3">
<h2 class="text-xl lg:text-2xl font-bold">
<a href="{% url 'parks:park_detail' park.slug %}"
class="bg-gradient-to-r from-gray-900 to-gray-700 dark:from-white dark:to-gray-300 bg-clip-text text-transparent hover:from-blue-600 hover:to-purple-600 dark:hover:from-blue-400 dark:hover:to-purple-400 transition-all duration-300">
{{ park.name }}
</a>
</h2>
{# Status Badge #}
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-semibold border
{% if park.status == 'operating' %}bg-green-50 text-green-700 border-green-200 dark:bg-green-900/20 dark:text-green-400 dark:border-green-800
{% elif park.status == 'closed' %}bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-400 dark:border-red-800
{% elif park.status == 'seasonal' %}bg-blue-50 text-blue-700 border-blue-200 dark:bg-blue-900/20 dark:text-blue-400 dark:border-blue-800
{% elif park.status == 'closed_temp' %}bg-yellow-50 text-yellow-700 border-yellow-200 dark:bg-yellow-900/20 dark:text-yellow-400 dark:border-yellow-800
{% elif park.status == 'closed_permanently' or park.status == 'closed_perm' %}bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-400 dark:border-red-800
{% elif park.status == 'under_construction' %}bg-blue-50 text-blue-700 border-blue-200 dark:bg-blue-900/20 dark:text-blue-400 dark:border-blue-800
{% else %}bg-gray-50 text-gray-700 border-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-600{% endif %}">
{{ park.get_status_display }}
</span>
</div>
{% if park.operator %}
<div class="text-base font-medium text-gray-600 dark:text-gray-400 mb-3">
{{ park.operator.name }}
</div>
{% endif %}
{% if park.description %}
<p class="text-gray-600 dark:text-gray-400 line-clamp-2 mb-4">
{{ park.description|truncatewords:30 }}
</p>
{% endif %}
</div>
{# Stats Section #}
{% if park.ride_count or park.coaster_count %}
<div class="flex items-center space-x-6 text-sm">
{% if park.ride_count %}
<div class="flex items-center space-x-2 px-4 py-2 bg-gradient-to-r from-blue-50 to-purple-50 dark:from-blue-900/20 dark:to-purple-900/20 rounded-lg border border-blue-200/50 dark:border-blue-800/50">
<svg class="w-5 h-5 text-blue-600 dark:text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"/>
</svg>
<span class="font-semibold text-blue-700 dark:text-blue-300">{{ park.ride_count }}</span>
<span class="text-blue-600 dark:text-blue-400">rides</span>
</div>
{% endif %}
{% if park.coaster_count %}
<div class="flex items-center space-x-2 px-4 py-2 bg-gradient-to-r from-purple-50 to-pink-50 dark:from-purple-900/20 dark:to-pink-900/20 rounded-lg border border-purple-200/50 dark:border-purple-800/50">
<svg class="w-5 h-5 text-purple-600 dark:text-purple-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>
</svg>
<span class="font-semibold text-purple-700 dark:text-purple-300">{{ park.coaster_count }}</span>
<span class="text-purple-600 dark:text-purple-400">coasters</span>
</div>
{% endif %}
</div>
{% endif %}
</div>
</div>
</article>
{% else %}
{# Enhanced Grid View Item #}
<article class="group bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm border border-gray-200/50 dark:border-gray-700/50 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 transform hover:scale-105 hover:-rotate-1 overflow-hidden {{ class }}">
{# Card Header with Gradient #}
<div class="h-2 bg-gradient-to-r from-blue-500 via-purple-500 to-pink-500"></div>
<div class="p-6">
<div class="flex items-start justify-between mb-4">
<h2 class="text-xl font-bold line-clamp-2 flex-1 mr-3">
<a href="{% url 'parks:park_detail' park.slug %}"
class="bg-gradient-to-r from-gray-900 to-gray-700 dark:from-white dark:to-gray-300 bg-clip-text text-transparent hover:from-blue-600 hover:to-purple-600 dark:hover:from-blue-400 dark:hover:to-purple-400 transition-all duration-300">
{{ park.name }}
</a>
</h2>
{# Status Badge #}
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-semibold border shrink-0
{% if park.status == 'operating' %}bg-green-50 text-green-700 border-green-200 dark:bg-green-900/20 dark:text-green-400 dark:border-green-800
{% elif park.status == 'closed' %}bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-400 dark:border-red-800
{% elif park.status == 'seasonal' %}bg-blue-50 text-blue-700 border-blue-200 dark:bg-blue-900/20 dark:text-blue-400 dark:border-blue-800
{% elif park.status == 'closed_temp' %}bg-yellow-50 text-yellow-700 border-yellow-200 dark:bg-yellow-900/20 dark:text-yellow-400 dark:border-yellow-800
{% elif park.status == 'closed_permanently' or park.status == 'closed_perm' %}bg-red-50 text-red-700 border-red-200 dark:bg-red-900/20 dark:text-red-400 dark:border-red-800
{% elif park.status == 'under_construction' %}bg-blue-50 text-blue-700 border-blue-200 dark:bg-blue-900/20 dark:text-blue-400 dark:border-blue-800
{% else %}bg-gray-50 text-gray-700 border-gray-200 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-600{% endif %}">
{{ park.get_status_display }}
</span>
</div>
{% if park.operator %}
<div class="text-sm font-medium text-gray-600 dark:text-gray-400 mb-3 truncate">
{{ park.operator.name }}
</div>
{% endif %}
{% if park.description %}
<p class="text-sm text-gray-600 dark:text-gray-400 line-clamp-3 mb-4">
{{ park.description|truncatewords:15 }}
</p>
{% endif %}
{# Stats Footer #}
{% if park.ride_count or park.coaster_count %}
<div class="flex items-center justify-between pt-4 border-t border-gray-200/50 dark:border-gray-600/50">
<div class="flex items-center space-x-4 text-sm">
{% if park.ride_count %}
<div class="flex items-center space-x-1 text-blue-600 dark:text-blue-400">
<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 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"/>
</svg>
<span class="font-semibold">{{ park.ride_count }}</span>
</div>
{% endif %}
{% if park.coaster_count %}
<div class="flex items-center space-x-1 text-purple-600 dark:text-purple-400">
<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="M13 10V3L4 14h7v7l9-11h-7z"/>
</svg>
<span class="font-semibold">{{ park.coaster_count }}</span>
</div>
{% endif %}
</div>
{# View Details Arrow #}
<div class="text-gray-400 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors duration-200">
<svg class="w-5 h-5 transform group-hover:translate-x-1 transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
</svg>
</div>
</div>
{% endif %}
</div>
</article>
{% endif %}
{% endif %}