Refactor search results template to utilize Alpine.js for view switching and state management. Enhanced view mode handling and integrated HTMX for improved search functionality.

This commit is contained in:
pacnpal
2025-09-26 13:50:31 -04:00
parent f8907c7778
commit d4431acb39

View File

@@ -41,9 +41,9 @@
<!-- Right side: View switching buttons --> <!-- Right side: View switching buttons -->
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<div class="flex bg-gray-100 dark:bg-gray-700 rounded-lg p-1" x-data="{ viewMode: '{{ request.GET.view_mode|default:'grid' }}' }"> <div class="flex bg-gray-100 dark:bg-gray-700 rounded-lg p-1" x-data="searchViewSwitcher">
<button type="button" <button type="button"
@click="viewMode = 'grid'; switchView('grid')" @click="switchView('grid')"
:class="viewMode === 'grid' ? 'bg-white dark:bg-gray-600 text-gray-900 dark:text-white shadow-sm' : 'text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300'" :class="viewMode === 'grid' ? 'bg-white dark:bg-gray-600 text-gray-900 dark:text-white shadow-sm' : 'text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300'"
class="flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors"> class="flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -51,7 +51,7 @@
</svg> </svg>
</button> </button>
<button type="button" <button type="button"
@click="viewMode = 'list'; switchView('list')" @click="switchView('list')"
:class="viewMode === 'list' ? 'bg-white dark:bg-gray-600 text-gray-900 dark:text-white shadow-sm' : 'text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300'" :class="viewMode === 'list' ? 'bg-white dark:bg-gray-600 text-gray-900 dark:text-white shadow-sm' : 'text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300'"
class="flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors"> class="flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -64,7 +64,7 @@
</div> </div>
<!-- Results Container --> <!-- Results Container -->
<div id="results-container" class="divide-y divide-gray-200 dark:divide-gray-700" x-data="{ viewMode: '{{ request.GET.view_mode|default:'grid' }}' }"> <div id="results-container" class="divide-y divide-gray-200 dark:divide-gray-700" x-data="searchResults">
<!-- Grid View --> <!-- Grid View -->
<div x-show="viewMode === 'grid'" class="p-6"> <div x-show="viewMode === 'grid'" class="p-6">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
@@ -235,64 +235,64 @@
</div> </div>
</div> </div>
{# Include required scripts #}
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
<script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
<script src="https://unpkg.com/unpoly@3/unpoly.min.js"></script>
<script> <script>
// View switching functionality document.addEventListener('alpine:init', () => {
function switchView(mode) { // Search View Switcher Component
// Update URL parameter Alpine.data('searchViewSwitcher', () => ({
const url = new URL(window.location); viewMode: '{{ request.GET.view_mode|default:"grid" }}',
url.searchParams.set('view_mode', mode);
// Update the URL without reloading init() {
window.history.pushState({}, '', url); // Initialize view mode from URL or localStorage
const urlParams = new URLSearchParams(window.location.search);
const urlViewMode = urlParams.get('view_mode');
const savedViewMode = localStorage.getItem('parkViewMode');
this.viewMode = urlViewMode || savedViewMode || 'grid';
// Store preference in localStorage // Set initial view mode in URL if not present
localStorage.setItem('parkViewMode', mode); if (!urlViewMode) {
} const url = new URL(window.location);
url.searchParams.set('view_mode', this.viewMode);
window.history.replaceState({}, '', url);
}
},
// Initialize view mode from URL or localStorage switchView(mode) {
document.addEventListener('DOMContentLoaded', function() { this.viewMode = mode;
const urlParams = new URLSearchParams(window.location.search);
const urlViewMode = urlParams.get('view_mode');
const savedViewMode = localStorage.getItem('parkViewMode');
const defaultViewMode = urlViewMode || savedViewMode || 'grid';
// Set initial view mode // Update URL parameter
if (!urlViewMode) { const url = new URL(window.location);
const url = new URL(window.location); url.searchParams.set('view_mode', mode);
url.searchParams.set('view_mode', defaultViewMode); window.history.pushState({}, '', url);
window.history.replaceState({}, '', url);
} // Store preference in localStorage
localStorage.setItem('parkViewMode', mode);
// Update results container view mode
this.$dispatch('view-mode-changed', { mode });
}
}));
// Search Results Component
Alpine.data('searchResults', () => ({
viewMode: '{{ request.GET.view_mode|default:"grid" }}',
init() {
// Listen for view mode changes
this.$el.addEventListener('view-mode-changed', (event) => {
this.viewMode = event.detail.mode;
});
}
}));
}); });
// Enhanced search functionality // Enhanced search functionality with HTMX integration
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
const searchInput = document.querySelector('input[name="search"]'); const searchInput = document.querySelector('input[name="search"]');
if (searchInput) { if (searchInput) {
let searchTimeout;
// Preserve view mode in search requests // Preserve view mode in search requests
searchInput.addEventListener('input', function(e) { searchInput.addEventListener('htmx:configRequest', function(event) {
clearTimeout(searchTimeout); const currentViewMode = new URLSearchParams(window.location.search).get('view_mode') || 'grid';
searchTimeout = setTimeout(() => { event.detail.parameters.view_mode = currentViewMode;
// Get current view mode
const currentViewMode = new URLSearchParams(window.location.search).get('view_mode') || 'grid';
// Add view mode to the HTMX request
const currentUrl = new URL(e.target.getAttribute('hx-get'), window.location.origin);
currentUrl.searchParams.set('view_mode', currentViewMode);
currentUrl.searchParams.set('search', e.target.value);
// Update the hx-get attribute
e.target.setAttribute('hx-get', currentUrl.pathname + currentUrl.search);
// Trigger the HTMX request
htmx.trigger(e.target, 'input');
}, 500);
}); });
} }
}); });