mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-21 05:51:08 -05:00
feat: Add detailed park and ride pages with HTMX integration
- Implemented park detail page with dynamic content loading for rides and weather. - Created park list page with filters and search functionality. - Developed ride detail page showcasing ride stats, reviews, and similar rides. - Added ride list page with filtering options and dynamic loading. - Introduced search results page with tabs for parks, rides, and users. - Added HTMX tests for global search functionality.
This commit is contained in:
111
static/js/stores/index.js
Normal file
111
static/js/stores/index.js
Normal file
@@ -0,0 +1,111 @@
|
||||
document.addEventListener('alpine:init', () => {
|
||||
// Authentication Store
|
||||
Alpine.store('auth', {
|
||||
user: null,
|
||||
isAuthenticated: false,
|
||||
permissions: [],
|
||||
|
||||
init() {
|
||||
// Initialize from server-rendered data
|
||||
if (window.__AUTH_USER__) {
|
||||
this.user = window.__AUTH_USER__;
|
||||
this.isAuthenticated = true;
|
||||
this.permissions = window.__AUTH_PERMISSIONS__ || [];
|
||||
}
|
||||
},
|
||||
|
||||
hasPermission(permission) {
|
||||
return this.permissions.includes(permission);
|
||||
}
|
||||
});
|
||||
|
||||
// Theme Store
|
||||
Alpine.store('theme', {
|
||||
isDark: false,
|
||||
|
||||
init() {
|
||||
this.isDark = localStorage.getItem('theme') === 'dark' ||
|
||||
(!localStorage.getItem('theme') &&
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
this.apply();
|
||||
},
|
||||
|
||||
toggle() {
|
||||
this.isDark = !this.isDark;
|
||||
this.apply();
|
||||
},
|
||||
|
||||
apply() {
|
||||
document.documentElement.classList.toggle('dark', this.isDark);
|
||||
localStorage.setItem('theme', this.isDark ? 'dark' : 'light');
|
||||
}
|
||||
});
|
||||
|
||||
// Search Store
|
||||
Alpine.store('search', {
|
||||
query: '',
|
||||
results: [],
|
||||
isOpen: false,
|
||||
isLoading: false,
|
||||
filters: {},
|
||||
|
||||
toggle() {
|
||||
this.isOpen = !this.isOpen;
|
||||
if (this.isOpen) {
|
||||
// Focus search input logic would go here
|
||||
}
|
||||
},
|
||||
|
||||
close() {
|
||||
this.isOpen = false;
|
||||
},
|
||||
|
||||
clearSearch() {
|
||||
this.query = '';
|
||||
this.results = [];
|
||||
}
|
||||
});
|
||||
|
||||
// Toast/Notification Store
|
||||
Alpine.store('toast', {
|
||||
toasts: [],
|
||||
|
||||
show(message, type = 'info', duration = 5000) {
|
||||
const id = Date.now();
|
||||
this.toasts.push({ id, message, type, duration });
|
||||
if (duration > 0) {
|
||||
setTimeout(() => this.dismiss(id), duration);
|
||||
}
|
||||
return id;
|
||||
},
|
||||
|
||||
dismiss(id) {
|
||||
this.toasts = this.toasts.filter(t => t.id !== id);
|
||||
},
|
||||
|
||||
success(message) { return this.show(message, 'success'); },
|
||||
error(message) { return this.show(message, 'error'); },
|
||||
warning(message) { return this.show(message, 'warning'); },
|
||||
info(message) { return this.show(message, 'info'); }
|
||||
});
|
||||
|
||||
// UI State Store
|
||||
Alpine.store('ui', {
|
||||
sidebarOpen: false,
|
||||
modalStack: [],
|
||||
|
||||
openModal(id) {
|
||||
if (!this.modalStack.includes(id)) {
|
||||
this.modalStack.push(id);
|
||||
}
|
||||
},
|
||||
closeModal(id) {
|
||||
this.modalStack = this.modalStack.filter(m => m !== id);
|
||||
},
|
||||
isModalOpen(id) { return this.modalStack.includes(id); },
|
||||
|
||||
toggleSidebar() {
|
||||
this.sidebarOpen = !this.sidebarOpen;
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user