mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-22 19:51:08 -05:00
Enhance search functionality with loading indicators, dark mode support, and improved UI; implement event handling for search results and refine park filter tests for better coverage
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
{% extends "search/layouts/filtered_list.html" %}
|
||||
{% load static %}
|
||||
{% load filter_utils %}
|
||||
|
||||
{% block page_title %}Parks{% endblock %}
|
||||
@@ -6,25 +7,14 @@
|
||||
{% block filter_errors %}
|
||||
{% if filter.errors %}
|
||||
<div class="bg-red-50 border-l-4 border-red-400 p-4 mb-4">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<svg class="h-5 w-5 text-red-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<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">Please correct the following errors:</h3>
|
||||
<div class="mt-2 text-sm text-red-700">
|
||||
<ul class="list-disc pl-5 space-y-1">
|
||||
{% for field, errors in filter.errors.items %}
|
||||
{% for error in errors %}
|
||||
<li>{{ field }}: {{ error }}</li>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="text-sm font-medium text-red-800">Please correct the following errors:</h3>
|
||||
<ul class="mt-2 text-sm text-red-700 list-disc pl-5 space-y-1">
|
||||
{% for field, errors in filter.errors.items %}
|
||||
{% for error in errors %}
|
||||
<li>{{ field }}: {{ error }}</li>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -44,12 +34,60 @@
|
||||
Browse and filter amusement parks, theme parks, and water parks from around the world.
|
||||
{% endblock %}
|
||||
|
||||
{% block filter_section_title %}Find Parks{% endblock %}
|
||||
{% block filter_section %}
|
||||
<div class="mb-6">
|
||||
{# Quick Search #}
|
||||
<div class="mb-8">
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<label for="search" class="sr-only">Search parks</label>
|
||||
<div class="relative">
|
||||
<input type="search"
|
||||
name="search"
|
||||
id="search"
|
||||
class="block w-full rounded-md border-gray-300 bg-white py-3 pl-4 pr-10 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500 sm:text-sm"
|
||||
placeholder="Search parks by name or location..."
|
||||
hx-get="{% url 'parks:search_parks' %}"
|
||||
hx-trigger="keyup changed delay:300ms, search"
|
||||
hx-target="#search-results"
|
||||
hx-indicator="#search-indicator"
|
||||
autocomplete="off">
|
||||
<div class="absolute inset-y-0 right-0 flex items-center pr-3">
|
||||
<div id="search-indicator" class="htmx-indicator">
|
||||
<svg class="h-5 w-5 text-gray-400 animate-spin" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none"/>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="search-results" class="mt-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% block results_section_title %}Parks{% endblock %}
|
||||
{# Advanced Filters #}
|
||||
<div class="bg-white shadow sm:rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<h3 class="text-lg font-medium leading-6 text-gray-900">Advanced Filters</h3>
|
||||
<div class="mt-4">
|
||||
{% include "search/partials/filter_form.html" with filter=filter %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block results_section_title %}All Parks{% endblock %}
|
||||
|
||||
{% block no_results_message %}
|
||||
<div class="text-center p-8 text-gray-500">
|
||||
No parks found matching your criteria. Try adjusting your filters or <a href="{% url 'parks:park_create' %}" class="text-blue-600 hover:underline">add a new park</a>.
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block results_section %}
|
||||
<div class="space-y-6">
|
||||
{% for park in parks %}
|
||||
{% include "search/partials/park_results.html" with park=park %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,35 +1,58 @@
|
||||
{% if error %}
|
||||
<div class="p-2 text-red-600">
|
||||
<div class="text-red-600 bg-red-50 p-4 rounded-md" role="alert">
|
||||
{{ error }}
|
||||
</div>
|
||||
{% else %}
|
||||
{% for park in parks %}
|
||||
<div class="p-2 hover:bg-gray-100 cursor-pointer">
|
||||
<div class="flex items-center space-x-3">
|
||||
{% if park.photos.exists %}
|
||||
<img src="{{ park.photos.first.image.url }}"
|
||||
alt="{{ park.name }}"
|
||||
class="w-8 h-8 object-cover rounded">
|
||||
{% else %}
|
||||
<div class="w-8 h-8 bg-gray-200 rounded flex items-center justify-center">
|
||||
<span class="text-xs text-gray-500">{{ park.name|first|upper }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div>
|
||||
<div class="font-medium">{{ park.name }}</div>
|
||||
{% with location=park.location.first %}
|
||||
{% if location %}
|
||||
<div class="text-sm text-gray-500">
|
||||
{{ location.city }}{% if location.state %}, {{ location.state }}{% endif %}
|
||||
<div class="space-y-4">
|
||||
{% for park in parks %}
|
||||
<div class="bg-white shadow sm:rounded-lg">
|
||||
<a href="{% url 'parks:park_detail' park.slug %}" class="block px-4 py-4 hover:bg-gray-50">
|
||||
<div class="flex items-start space-x-4">
|
||||
{% if park.photos.exists %}
|
||||
<img src="{{ park.photos.first.image.url }}"
|
||||
alt="{{ park.name }}"
|
||||
class="h-20 w-20 object-cover rounded-lg">
|
||||
{% else %}
|
||||
<div class="h-20 w-20 bg-gray-100 rounded-lg flex items-center justify-center">
|
||||
<span class="text-2xl font-medium text-gray-400">{{ park.name|first|upper }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex justify-between">
|
||||
<h3 class="font-medium text-gray-900">{{ park.name }}</h3>
|
||||
<span class="inline-flex items-center rounded-full px-2 py-1 text-xs font-medium {{ park.get_status_color }}">
|
||||
{{ park.get_status_display }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{% with location=park.location.first %}
|
||||
{% if location %}
|
||||
<p class="mt-1 text-sm text-gray-500">
|
||||
{{ location.city }}{% if location.state %}, {{ location.state }}{% endif %}
|
||||
{% if location.country %}, {{ location.country }}{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<div class="mt-2 flex items-center space-x-2 text-sm text-gray-500">
|
||||
{% if park.ride_count %}
|
||||
<span>{{ park.ride_count }} rides</span>
|
||||
{% endif %}
|
||||
|
||||
{% if park.coaster_count %}
|
||||
<span>•</span>
|
||||
<span>{{ park.coaster_count }} coasters</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="text-center py-8 bg-white shadow sm:rounded-lg">
|
||||
<p class="text-gray-500">No parks found matching your search.</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="p-2 text-gray-500 text-center">
|
||||
No parks found
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
Reference in New Issue
Block a user