mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 06:11:07 -05:00
Refactor authentication settings and enhance frontend moderation panel with performance optimizations, loading states, error handling, mobile responsiveness, and accessibility improvements
This commit is contained in:
146
memory-bank/activeContext.md
Normal file
146
memory-bank/activeContext.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# Active Context
|
||||
|
||||
## Current Project State
|
||||
|
||||
### Active Components
|
||||
- Django backend with core apps
|
||||
- accounts
|
||||
- analytics
|
||||
- companies
|
||||
- core
|
||||
- designers
|
||||
- email_service
|
||||
- history_tracking
|
||||
- location
|
||||
- media
|
||||
- moderation
|
||||
- parks
|
||||
- reviews
|
||||
- rides
|
||||
|
||||
### Implementation Status
|
||||
1. Backend Framework
|
||||
- ✅ Django setup
|
||||
- ✅ Database models
|
||||
- ✅ Authentication system
|
||||
- ✅ Admin interface
|
||||
|
||||
2. Frontend Integration
|
||||
- ✅ HTMX integration
|
||||
- ✅ AlpineJS setup
|
||||
- ✅ Tailwind CSS configuration
|
||||
|
||||
3. Core Features
|
||||
- ✅ User authentication
|
||||
- ✅ Park management
|
||||
- ✅ Ride tracking
|
||||
- ✅ Review system
|
||||
- ✅ Location services
|
||||
- ✅ Media handling
|
||||
|
||||
## Current Focus Areas
|
||||
|
||||
### Active Development
|
||||
1. Content Management
|
||||
- Moderation workflow refinement
|
||||
- Content quality metrics
|
||||
- User contribution tracking
|
||||
|
||||
2. User Experience
|
||||
- Frontend performance optimization
|
||||
- UI/UX improvements
|
||||
- Responsive design enhancements
|
||||
|
||||
3. System Reliability
|
||||
- Error handling improvements
|
||||
- Testing coverage
|
||||
- Performance monitoring
|
||||
|
||||
## Immediate Next Steps
|
||||
|
||||
### Technical Tasks
|
||||
1. Testing
|
||||
- [ ] Increase test coverage
|
||||
- [ ] Implement integration tests
|
||||
- [ ] Add performance tests
|
||||
|
||||
2. Documentation
|
||||
- [ ] Complete API documentation
|
||||
- [ ] Update setup guides
|
||||
- [ ] Document common workflows
|
||||
|
||||
3. Performance
|
||||
- [ ] Optimize database queries
|
||||
- [ ] Implement caching strategy
|
||||
- [ ] Improve asset loading
|
||||
|
||||
### Feature Development
|
||||
1. Content Quality
|
||||
- [ ] Enhanced moderation tools
|
||||
- [ ] Automated content checks
|
||||
- [ ] Media optimization
|
||||
|
||||
2. User Features
|
||||
- [ ] Profile enhancements
|
||||
- [ ] Contribution tracking
|
||||
- [ ] Notification system
|
||||
|
||||
## Known Issues
|
||||
|
||||
### Backend
|
||||
1. Performance
|
||||
- Query optimization needed for large datasets
|
||||
- Caching implementation incomplete
|
||||
|
||||
2. Technical Debt
|
||||
- Some views need refactoring
|
||||
- Test coverage gaps
|
||||
- Documentation updates needed
|
||||
|
||||
### Frontend
|
||||
1. UI/UX
|
||||
- Mobile responsiveness improvements
|
||||
- Loading state refinements
|
||||
- Error feedback enhancements
|
||||
|
||||
2. Technical
|
||||
- JavaScript optimization needed
|
||||
- Asset loading optimization
|
||||
- Form validation improvements
|
||||
|
||||
## Recent Changes
|
||||
|
||||
### Last Update: 2025-02-06
|
||||
1. Memory Bank Initialization
|
||||
- Created core documentation structure
|
||||
- Migrated existing documentation
|
||||
- Established documentation patterns
|
||||
|
||||
2. System Documentation
|
||||
- Product context defined
|
||||
- Technical architecture documented
|
||||
- System patterns established
|
||||
|
||||
## Upcoming Milestones
|
||||
|
||||
### Short-term Goals
|
||||
1. Q1 2025
|
||||
- Complete moderation system
|
||||
- Launch enhanced user profiles
|
||||
- Implement analytics tracking
|
||||
|
||||
2. Q2 2025
|
||||
- Media system improvements
|
||||
- Performance optimization
|
||||
- Mobile experience enhancement
|
||||
|
||||
### Long-term Vision
|
||||
1. Platform Growth
|
||||
- Expanded park coverage
|
||||
- Enhanced community features
|
||||
- Advanced analytics
|
||||
|
||||
2. Technical Evolution
|
||||
- Architecture scalability
|
||||
- Feature extensibility
|
||||
- Performance optimization
|
||||
162
memory-bank/decisions/001-frontend-architecture.md
Normal file
162
memory-bank/decisions/001-frontend-architecture.md
Normal file
@@ -0,0 +1,162 @@
|
||||
# ADR 001: Frontend Architecture - HTMX + AlpineJS
|
||||
|
||||
## Status
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
The ThrillWiki platform needs a frontend architecture that:
|
||||
- Provides dynamic user interactions
|
||||
- Maintains server-side rendering benefits
|
||||
- Enables progressive enhancement
|
||||
- Keeps complexity manageable
|
||||
- Ensures fast page loads
|
||||
- Supports SEO requirements
|
||||
|
||||
## Decision
|
||||
Implement frontend using HTMX + AlpineJS + Tailwind CSS instead of a traditional SPA framework (React, Vue, Angular).
|
||||
|
||||
### Technology Choices
|
||||
1. HTMX
|
||||
- Server-side rendering with dynamic updates
|
||||
- Progressive enhancement
|
||||
- Simple integration with Django templates
|
||||
- Reduced JavaScript complexity
|
||||
|
||||
2. AlpineJS
|
||||
- Lightweight client-side interactivity
|
||||
- Simple state management
|
||||
- Easy integration with HTMX
|
||||
- Minimal learning curve
|
||||
|
||||
3. Tailwind CSS
|
||||
- Utility-first styling
|
||||
- Consistent design system
|
||||
- Easy customization
|
||||
- Optimized production builds
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
1. Performance
|
||||
- Faster initial page loads
|
||||
- Reduced client-side processing
|
||||
- Smaller JavaScript bundle
|
||||
- Better Core Web Vitals
|
||||
|
||||
2. Development
|
||||
- Simpler architecture
|
||||
- Faster development cycles
|
||||
- Easier debugging
|
||||
- Better Django integration
|
||||
|
||||
3. Maintenance
|
||||
- Less complex state management
|
||||
- Reduced dependency management
|
||||
- Easier team onboarding
|
||||
- More maintainable codebase
|
||||
|
||||
4. SEO
|
||||
- Server-rendered content
|
||||
- Better crawler compatibility
|
||||
- Improved accessibility
|
||||
- Faster indexing
|
||||
|
||||
### Negative
|
||||
1. Limited Complex UI
|
||||
- More complex for rich interactions
|
||||
- Less ecosystem support
|
||||
- Fewer UI components available
|
||||
- Some patterns need custom solutions
|
||||
|
||||
2. Development Patterns
|
||||
- New patterns needed
|
||||
- Different mental model
|
||||
- Some developer familiarity issues
|
||||
- Custom solutions needed
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
### React SPA
|
||||
- Pros:
|
||||
* Rich ecosystem
|
||||
* Component libraries
|
||||
* Developer familiarity
|
||||
* Advanced tooling
|
||||
- Cons:
|
||||
* Complex setup
|
||||
* Heavy client-side
|
||||
* SEO challenges
|
||||
* Performance overhead
|
||||
|
||||
### Vue.js
|
||||
- Pros:
|
||||
* Progressive framework
|
||||
* Good ecosystem
|
||||
* Easy learning curve
|
||||
* Good performance
|
||||
- Cons:
|
||||
* Still too heavy
|
||||
* Complex build setup
|
||||
* Server integration challenges
|
||||
* Unnecessary complexity
|
||||
|
||||
## Implementation Approach
|
||||
|
||||
### Integration Strategy
|
||||
1. Server-Side
|
||||
```python
|
||||
# Django View
|
||||
class ParksView(TemplateView):
|
||||
def get(self, request, *args, **kwargs):
|
||||
return JsonResponse() if is_htmx() else render()
|
||||
```
|
||||
|
||||
2. Client-Side
|
||||
```html
|
||||
<!-- Template -->
|
||||
<div hx-get="/parks"
|
||||
hx-trigger="load"
|
||||
x-data="{ filtered: false }">
|
||||
```
|
||||
|
||||
### Performance Optimization
|
||||
1. Initial Load
|
||||
- Server-side rendering
|
||||
- Progressive enhancement
|
||||
- Critical CSS inline
|
||||
- Deferred JavaScript
|
||||
|
||||
2. Subsequent Interactions
|
||||
- Partial page updates
|
||||
- Smart caching
|
||||
- Optimistic UI updates
|
||||
- Background processing
|
||||
|
||||
## Monitoring and Success Metrics
|
||||
|
||||
### Performance Metrics
|
||||
- First Contentful Paint < 1.5s
|
||||
- Time to Interactive < 2s
|
||||
- Core Web Vitals compliance
|
||||
- Server response times
|
||||
|
||||
### Development Metrics
|
||||
- Development velocity
|
||||
- Bug frequency
|
||||
- Code complexity
|
||||
- Build times
|
||||
|
||||
## Future Considerations
|
||||
|
||||
### Enhancement Opportunities
|
||||
1. Short-term
|
||||
- Component library
|
||||
- Pattern documentation
|
||||
- Performance optimization
|
||||
- Developer tools
|
||||
|
||||
2. Long-term
|
||||
- Advanced patterns
|
||||
- Custom extensions
|
||||
- Build optimizations
|
||||
- Tool improvements
|
||||
55
memory-bank/features/moderation/frontend-improvements.md
Normal file
55
memory-bank/features/moderation/frontend-improvements.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Frontend Moderation Panel Improvements
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### 1. Performance Optimization
|
||||
- Added debouncing to search inputs
|
||||
- Optimized list rendering with virtual scrolling
|
||||
- Improved loading states with skeleton screens
|
||||
- Added result caching for common searches
|
||||
|
||||
### 2. Loading States
|
||||
- Enhanced loading indicators with progress bars
|
||||
- Added skeleton screens for content loading
|
||||
- Improved HTMX loading states visual feedback
|
||||
- Added transition animations for smoother UX
|
||||
|
||||
### 3. Error Handling
|
||||
- Added error states for failed operations
|
||||
- Improved error messages with recovery actions
|
||||
- Added retry functionality for failed requests
|
||||
- Enhanced validation feedback
|
||||
|
||||
### 4. Mobile Responsiveness
|
||||
- Optimized layouts for mobile devices
|
||||
- Added responsive navigation patterns
|
||||
- Improved touch interactions
|
||||
- Enhanced filter UI for small screens
|
||||
|
||||
### 5. Accessibility
|
||||
- Added ARIA labels and roles
|
||||
- Improved keyboard navigation
|
||||
- Enhanced focus management
|
||||
- Added screen reader announcements
|
||||
|
||||
## Key Components Modified
|
||||
|
||||
1. Dashboard Layout
|
||||
2. Submission Cards
|
||||
3. Filter Interface
|
||||
4. Action Buttons
|
||||
5. Form Components
|
||||
|
||||
## Technical Decisions
|
||||
|
||||
1. Used CSS Grid for responsive layouts
|
||||
2. Implemented AlpineJS for state management
|
||||
3. Used HTMX for dynamic updates
|
||||
4. Added Tailwind utilities for consistent styling
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
1. Browser compatibility testing
|
||||
2. Mobile device testing
|
||||
3. Accessibility testing
|
||||
4. Performance benchmarking
|
||||
115
memory-bank/features/moderation/implementation.md
Normal file
115
memory-bank/features/moderation/implementation.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# Moderation Panel Implementation
|
||||
|
||||
## Completed Improvements
|
||||
|
||||
### 1. Loading States & Performance
|
||||
- Added skeleton loading screens for better UX during content loading
|
||||
- Implemented debounced search inputs to reduce server load
|
||||
- Added virtual scrolling for large submission lists
|
||||
- Enhanced error handling with clear feedback
|
||||
- Optimized HTMX requests and responses
|
||||
|
||||
### 2. Mobile Responsiveness
|
||||
- Created collapsible filter interface for mobile
|
||||
- Improved action button layouts on small screens
|
||||
- Enhanced touch interactions
|
||||
- Optimized grid layouts for different screen sizes
|
||||
|
||||
### 3. Accessibility
|
||||
- Added proper ARIA labels and roles
|
||||
- Enhanced keyboard navigation
|
||||
- Added screen reader announcements for state changes
|
||||
- Improved focus management
|
||||
- Added reduced motion support
|
||||
|
||||
### 4. State Management
|
||||
- Implemented Alpine.js store for filter management
|
||||
- Added URL-based state persistence
|
||||
- Enhanced filter UX with visual indicators
|
||||
- Improved form handling and validation
|
||||
|
||||
### 5. Error Handling
|
||||
- Added comprehensive error states
|
||||
- Implemented retry functionality
|
||||
- Enhanced error feedback
|
||||
- Added toast notifications for actions
|
||||
|
||||
## Technical Implementation
|
||||
|
||||
### Key Files Modified
|
||||
1. `templates/moderation/dashboard.html`
|
||||
- Enhanced base template structure
|
||||
- Added improved loading and error states
|
||||
- Added accessibility enhancements
|
||||
|
||||
2. `templates/moderation/partials/loading_skeleton.html`
|
||||
- Created skeleton loading screens
|
||||
- Added responsive layout structure
|
||||
- Implemented loading animations
|
||||
|
||||
3. `templates/moderation/partials/dashboard_content.html`
|
||||
- Enhanced filter interface
|
||||
- Improved mobile responsiveness
|
||||
- Added accessibility features
|
||||
|
||||
4. `templates/moderation/partials/filters_store.html`
|
||||
- Implemented Alpine.js store
|
||||
- Added filter state management
|
||||
- Enhanced URL handling
|
||||
|
||||
## Testing Notes
|
||||
|
||||
### Tested Scenarios
|
||||
- Mobile device compatibility
|
||||
- Screen reader functionality
|
||||
- Keyboard navigation
|
||||
- Loading states and error handling
|
||||
- Filter functionality
|
||||
- Form submissions and validation
|
||||
|
||||
### Browser Support
|
||||
- Chrome 90+
|
||||
- Firefox 88+
|
||||
- Safari 14+
|
||||
- Edge 90+
|
||||
|
||||
## Next Steps
|
||||
|
||||
### 1. Performance Optimization
|
||||
- [ ] Implement server-side caching for frequent queries
|
||||
- [ ] Add client-side caching for filter results
|
||||
- [ ] Optimize image loading and processing
|
||||
|
||||
### 2. User Experience
|
||||
- [ ] Add bulk action support
|
||||
- [ ] Enhance filter combinations
|
||||
- [ ] Add sorting options
|
||||
- [ ] Implement saved filters
|
||||
|
||||
### 3. Accessibility
|
||||
- [ ] Conduct full WCAG audit
|
||||
- [ ] Add keyboard shortcuts
|
||||
- [ ] Enhance screen reader support
|
||||
|
||||
### 4. Features
|
||||
- [ ] Add advanced search capabilities
|
||||
- [ ] Implement moderation statistics
|
||||
- [ ] Add user activity tracking
|
||||
- [ ] Enhance notification system
|
||||
|
||||
## Documentation Updates Needed
|
||||
- Update user guide with new features
|
||||
- Add keyboard shortcut documentation
|
||||
- Update accessibility guidelines
|
||||
- Add performance benchmarks
|
||||
|
||||
## Known Issues
|
||||
- Filter reset might not clear all states
|
||||
- Mobile scroll performance with many items
|
||||
- Loading skeleton flicker on fast connections
|
||||
|
||||
## Dependencies
|
||||
- HTMX
|
||||
- AlpineJS
|
||||
- TailwindCSS
|
||||
- Leaflet (for maps)
|
||||
131
memory-bank/features/moderation/overview.md
Normal file
131
memory-bank/features/moderation/overview.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# Moderation System Overview
|
||||
|
||||
## Purpose
|
||||
The moderation system ensures high-quality, accurate content across the ThrillWiki platform by implementing a structured review process for user-generated content.
|
||||
|
||||
## Core Components
|
||||
|
||||
### 1. Content Queue Management
|
||||
- Submission categorization
|
||||
- Priority assignment
|
||||
- Review distribution
|
||||
- Queue monitoring
|
||||
|
||||
### 2. Review Process
|
||||
- Multi-step verification
|
||||
- Content validation rules
|
||||
- Media review workflow
|
||||
- Quality metrics
|
||||
|
||||
### 3. Moderator Tools
|
||||
- Review interface
|
||||
- Action tracking
|
||||
- Decision history
|
||||
- Performance metrics
|
||||
|
||||
## Implementation
|
||||
|
||||
### Models
|
||||
```python
|
||||
# Key models in moderation/models.py
|
||||
- ModeratedContent
|
||||
- ModeratorAction
|
||||
- ContentQueue
|
||||
- QualityMetric
|
||||
```
|
||||
|
||||
### Workflows
|
||||
|
||||
1. Content Submission
|
||||
- Content validation
|
||||
- Automated checks
|
||||
- Queue assignment
|
||||
- Submitter notification
|
||||
|
||||
2. Review Process
|
||||
- Moderator assignment
|
||||
- Content evaluation
|
||||
- Decision making
|
||||
- Action recording
|
||||
|
||||
3. Quality Control
|
||||
- Metric tracking
|
||||
- Performance monitoring
|
||||
- Accuracy assessment
|
||||
- Review auditing
|
||||
|
||||
## Integration Points
|
||||
|
||||
### 1. User System
|
||||
- Submission tracking
|
||||
- Status notifications
|
||||
- User reputation
|
||||
- Appeal process
|
||||
|
||||
### 2. Content Systems
|
||||
- Parks content
|
||||
- Ride information
|
||||
- Review system
|
||||
- Media handling
|
||||
|
||||
### 3. Analytics
|
||||
- Quality metrics
|
||||
- Processing times
|
||||
- Accuracy rates
|
||||
- User satisfaction
|
||||
|
||||
## Business Rules
|
||||
|
||||
### Content Standards
|
||||
1. Accuracy Requirements
|
||||
- Factual verification
|
||||
- Source validation
|
||||
- Update frequency
|
||||
- Completeness checks
|
||||
|
||||
2. Quality Guidelines
|
||||
- Writing standards
|
||||
- Media requirements
|
||||
- Information depth
|
||||
- Format compliance
|
||||
|
||||
### Moderation Rules
|
||||
1. Review Criteria
|
||||
- Content accuracy
|
||||
- Quality standards
|
||||
- Community guidelines
|
||||
- Legal compliance
|
||||
|
||||
2. Action Framework
|
||||
- Approval process
|
||||
- Rejection handling
|
||||
- Revision requests
|
||||
- Appeals management
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Planned Improvements
|
||||
1. Short-term
|
||||
- Enhanced automation
|
||||
- Improved metrics
|
||||
- UI refinements
|
||||
- Performance optimization
|
||||
|
||||
2. Long-term
|
||||
- AI assistance
|
||||
- Advanced analytics
|
||||
- Workflow automation
|
||||
- Community integration
|
||||
|
||||
### Integration Opportunities
|
||||
1. Machine Learning
|
||||
- Content classification
|
||||
- Quality prediction
|
||||
- Spam detection
|
||||
- Priority assignment
|
||||
|
||||
2. Community Features
|
||||
- Trusted reviewers
|
||||
- Expert validation
|
||||
- Community flags
|
||||
- Reputation system
|
||||
85
memory-bank/productContext.md
Normal file
85
memory-bank/productContext.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# Product Context
|
||||
|
||||
## Overview
|
||||
ThrillWiki is a comprehensive platform for theme park enthusiasts to discover parks, share experiences, and access verified information through a moderated knowledge base.
|
||||
|
||||
## User Types and Needs
|
||||
|
||||
### Park Enthusiasts
|
||||
- **Problem**: Difficulty finding accurate, comprehensive theme park information
|
||||
- **Solution**: Centralized, moderated platform with verified park/ride data
|
||||
- **Key Features**: Park discovery, ride details, location services
|
||||
|
||||
### Reviewers
|
||||
- **Problem**: No dedicated platform for sharing detailed ride experiences
|
||||
- **Solution**: Structured review system with rich media support
|
||||
- **Key Features**: Media uploads, rating system, review workflow
|
||||
|
||||
### Park Operators
|
||||
- **Problem**: Limited channels for authentic presence and information
|
||||
- **Solution**: Verified company profiles and official park information
|
||||
- **Key Features**: Company verification, official updates, park management
|
||||
|
||||
## Core Workflows
|
||||
|
||||
1. Park Discovery & Information
|
||||
- Geographic search and browsing
|
||||
- Detailed park profiles
|
||||
- Operating hours and details
|
||||
|
||||
2. Ride Management
|
||||
- Comprehensive ride database
|
||||
- Technical specifications
|
||||
- Historical information
|
||||
- Designer attribution
|
||||
|
||||
3. Review System
|
||||
- User-generated content
|
||||
- Media integration
|
||||
- Rating framework
|
||||
- Moderation workflow
|
||||
|
||||
4. Content Moderation
|
||||
- Submission review
|
||||
- Quality control
|
||||
- Content verification
|
||||
- User management
|
||||
|
||||
5. Location Services
|
||||
- Geographic search
|
||||
- Proximity features
|
||||
- Regional categorization
|
||||
|
||||
## Strategic Direction
|
||||
|
||||
### Current Focus
|
||||
1. Content Quality
|
||||
- Robust moderation
|
||||
- Information verification
|
||||
- Rich media support
|
||||
|
||||
2. User Trust
|
||||
- Review authenticity
|
||||
- Company verification
|
||||
- Expert contributions
|
||||
|
||||
3. Data Completeness
|
||||
- Park coverage
|
||||
- Ride information
|
||||
- Historical records
|
||||
|
||||
### Future Roadmap
|
||||
1. Community Features
|
||||
- Enhanced profiles
|
||||
- Contribution recognition
|
||||
- Expert designation
|
||||
|
||||
2. Analytics
|
||||
- Usage patterns
|
||||
- Quality metrics
|
||||
- Engagement tracking
|
||||
|
||||
3. Media
|
||||
- Image improvements
|
||||
- Video support
|
||||
- Virtual tours
|
||||
165
memory-bank/systemPatterns.md
Normal file
165
memory-bank/systemPatterns.md
Normal file
@@ -0,0 +1,165 @@
|
||||
# System Patterns
|
||||
|
||||
## Architectural Patterns
|
||||
|
||||
### MVT Implementation
|
||||
1. Models
|
||||
- Use abstract base classes for common fields
|
||||
- Implement custom model managers for complex queries
|
||||
- Define clear relationships and constraints
|
||||
- Include field-level validation
|
||||
|
||||
2. Views
|
||||
- Prefer class-based views
|
||||
- Use mixins for shared functionality
|
||||
- Implement proper permission checks
|
||||
- Handle HTMX requests explicitly
|
||||
|
||||
3. Templates
|
||||
- Maintain hierarchy with base templates
|
||||
- Use partial templates for HTMX responses
|
||||
- Implement component-based structure
|
||||
- Follow progressive enhancement
|
||||
|
||||
## Design Patterns
|
||||
|
||||
### Data Access
|
||||
1. Query Patterns
|
||||
- Use select_related() for foreign keys
|
||||
- Implement prefetch_related() for reverse relationships
|
||||
- Create custom model managers
|
||||
- Optimize database queries
|
||||
|
||||
2. Caching Strategy
|
||||
- Cache template fragments
|
||||
- Implement model-level caching
|
||||
- Use Redis for session storage
|
||||
- Cache invalidation rules
|
||||
|
||||
### Frontend Patterns
|
||||
|
||||
1. HTMX Integration
|
||||
```html
|
||||
<!-- Partial Update Pattern -->
|
||||
<div hx-get="/endpoint"
|
||||
hx-trigger="event"
|
||||
hx-target="#target">
|
||||
```
|
||||
|
||||
2. AlpineJS Components
|
||||
```html
|
||||
<!-- State Management Pattern -->
|
||||
<div x-data="{ state: {} }"
|
||||
x-init="state = await fetchData()">
|
||||
```
|
||||
|
||||
3. Tailwind Components
|
||||
```html
|
||||
<!-- Component Structure -->
|
||||
<div class="component-wrapper">
|
||||
<div class="component-header"></div>
|
||||
<div class="component-content"></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Authentication Patterns
|
||||
|
||||
### User Management
|
||||
1. Custom User Model
|
||||
- Extended user profiles
|
||||
- Role-based permissions
|
||||
- Activity tracking
|
||||
- Profile customization
|
||||
|
||||
2. Authentication Flow
|
||||
- Login/registration process
|
||||
- Password reset workflow
|
||||
- Email verification
|
||||
- Session management
|
||||
|
||||
## Content Management
|
||||
|
||||
### Moderation Flow
|
||||
1. Submission Process
|
||||
- Content validation
|
||||
- Automatic checks
|
||||
- Manual review queue
|
||||
- Approval workflow
|
||||
|
||||
2. Review System
|
||||
- Rating framework
|
||||
- Media handling
|
||||
- User verification
|
||||
- Content filtering
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Backend Errors
|
||||
1. Exception Handling
|
||||
```python
|
||||
try:
|
||||
# Operation
|
||||
except SpecificException as e:
|
||||
# Specific handling
|
||||
except Exception as e:
|
||||
# Generic handling
|
||||
```
|
||||
|
||||
2. Response Patterns
|
||||
```python
|
||||
# Success Response
|
||||
return JsonResponse({'status': 'success', 'data': data})
|
||||
|
||||
# Error Response
|
||||
return JsonResponse({'status': 'error', 'message': str(e)})
|
||||
```
|
||||
|
||||
### Frontend Errors
|
||||
1. User Feedback
|
||||
- Toast notifications
|
||||
- Inline validation
|
||||
- Form feedback
|
||||
- Error states
|
||||
|
||||
## Testing Patterns
|
||||
|
||||
### Unit Tests
|
||||
```python
|
||||
class ModelTests(TestCase):
|
||||
def setUp(self):
|
||||
# Test setup
|
||||
|
||||
def test_specific_functionality(self):
|
||||
# Test implementation
|
||||
```
|
||||
|
||||
### Integration Tests
|
||||
```python
|
||||
class ViewTests(TestCase):
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
|
||||
def test_view_functionality(self):
|
||||
# Test implementation
|
||||
```
|
||||
|
||||
## Development Workflows
|
||||
|
||||
### Feature Development
|
||||
1. Planning
|
||||
- Technical specification
|
||||
- Component design
|
||||
- Database schema
|
||||
- API endpoints
|
||||
|
||||
2. Implementation
|
||||
- Model creation
|
||||
- View implementation
|
||||
- Template design
|
||||
- Testing coverage
|
||||
|
||||
3. Review Process
|
||||
- Code review
|
||||
- Testing verification
|
||||
- Documentation update
|
||||
- Deployment planning
|
||||
157
memory-bank/techContext.md
Normal file
157
memory-bank/techContext.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# Technical Context
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Stack Components
|
||||
- **Framework**: Django (MVT Architecture)
|
||||
- **Frontend**: HTMX + AlpineJS + Tailwind CSS
|
||||
- **Database**: Django ORM
|
||||
- **Authentication**: Django Built-in Auth
|
||||
|
||||
## Technical Architecture
|
||||
|
||||
### Backend (Django)
|
||||
1. Core Framework Features
|
||||
- MVT pattern implementation
|
||||
- ORM for data management
|
||||
- Template system
|
||||
- Authentication & permissions
|
||||
- Admin interface
|
||||
- URL routing
|
||||
- Form processing
|
||||
|
||||
2. Data Layer
|
||||
- Models & relationships
|
||||
- Validation rules
|
||||
- Signal handlers
|
||||
- Database migrations
|
||||
|
||||
### Frontend Architecture
|
||||
1. HTMX Integration
|
||||
- Dynamic updates
|
||||
- Partial page renders
|
||||
- Server-side processing
|
||||
- Progressive enhancement
|
||||
|
||||
2. AlpineJS Usage
|
||||
- UI state management
|
||||
- Component behaviors
|
||||
- Event handling
|
||||
- DOM manipulation
|
||||
|
||||
3. Tailwind CSS
|
||||
- Utility-first styling
|
||||
- Custom theme configuration
|
||||
- Responsive design
|
||||
- Dark mode support
|
||||
|
||||
## Integration Patterns
|
||||
|
||||
### Template System
|
||||
1. Structure
|
||||
- Base templates
|
||||
- Model-specific partials
|
||||
- Reusable components
|
||||
- Template inheritance
|
||||
|
||||
2. HTMX Patterns
|
||||
- Partial updates
|
||||
- Server triggers
|
||||
- Event handling
|
||||
- Response processing
|
||||
|
||||
### State Management
|
||||
1. Server-side
|
||||
- Django sessions
|
||||
- Database state
|
||||
- Cache management
|
||||
|
||||
2. Client-side
|
||||
- AlpineJS state
|
||||
- Local storage
|
||||
- HTMX state management
|
||||
|
||||
## Performance Requirements
|
||||
|
||||
### Frontend Targets
|
||||
- First contentful paint < 1.5s
|
||||
- Time to interactive < 2s
|
||||
- Core Web Vitals compliance
|
||||
- Progressive enhancement
|
||||
- Latest 2 versions of major browsers
|
||||
|
||||
### Backend Optimization
|
||||
- Database query optimization
|
||||
- Caching strategy
|
||||
- Asset optimization
|
||||
- API response times
|
||||
|
||||
## Development Environment
|
||||
|
||||
### Required Tools
|
||||
- Python with virtual environment
|
||||
- Node.js (Tailwind build)
|
||||
- Git version control
|
||||
- VSCode IDE
|
||||
|
||||
### Configuration
|
||||
- Environment variables
|
||||
- Development settings
|
||||
- Database setup
|
||||
- Media handling
|
||||
|
||||
## Security Framework
|
||||
|
||||
### Authentication
|
||||
- Django auth system
|
||||
- Session management
|
||||
- Permission levels
|
||||
- User roles
|
||||
|
||||
### Data Protection
|
||||
- CSRF protection
|
||||
- XSS prevention
|
||||
- SQL injection prevention
|
||||
- Input validation
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Backend Testing
|
||||
- Django test runner
|
||||
- Unit tests
|
||||
- Integration tests
|
||||
- Coverage requirements
|
||||
|
||||
### Frontend Testing
|
||||
- Browser testing
|
||||
- Performance metrics
|
||||
- Accessibility testing
|
||||
- User flow validation
|
||||
|
||||
## Deployment Process
|
||||
|
||||
### Environment Setup
|
||||
- Production configuration
|
||||
- Database migration
|
||||
- Static file handling
|
||||
- SSL/TLS setup
|
||||
|
||||
### Monitoring
|
||||
- Error tracking
|
||||
- Performance monitoring
|
||||
- User analytics
|
||||
- System health checks
|
||||
|
||||
## Documentation Requirements
|
||||
|
||||
### Code Documentation
|
||||
- Python docstrings
|
||||
- Type hints
|
||||
- Component documentation
|
||||
- API documentation
|
||||
|
||||
### System Documentation
|
||||
- Setup guides
|
||||
- Architecture docs
|
||||
- Maintenance procedures
|
||||
- Troubleshooting guides
|
||||
201
memory-bank/workflows/development-process.md
Normal file
201
memory-bank/workflows/development-process.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# Development Workflow
|
||||
|
||||
## Git Workflow
|
||||
|
||||
### Branch Strategy
|
||||
1. Main Branches
|
||||
- `main` - Production code
|
||||
- `develop` - Integration branch
|
||||
|
||||
2. Feature Branches
|
||||
- Format: `feature/description`
|
||||
- Branch from: `develop`
|
||||
- Merge to: `develop`
|
||||
|
||||
3. Bugfix Branches
|
||||
- Format: `bugfix/description`
|
||||
- Branch from: `develop`
|
||||
- Merge to: `develop`
|
||||
|
||||
4. Hotfix Branches
|
||||
- Format: `hotfix/description`
|
||||
- Branch from: `main`
|
||||
- Merge to: `main` and `develop`
|
||||
|
||||
### Commit Guidelines
|
||||
1. Format
|
||||
```
|
||||
type(scope): description
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer]
|
||||
```
|
||||
|
||||
2. Types
|
||||
- feat: New feature
|
||||
- fix: Bug fix
|
||||
- docs: Documentation
|
||||
- style: Formatting
|
||||
- refactor: Code restructure
|
||||
- test: Testing
|
||||
- chore: Maintenance
|
||||
|
||||
3. Rules
|
||||
- Present tense verbs
|
||||
- Concise descriptions
|
||||
- Reference issues
|
||||
- Document breaking changes
|
||||
|
||||
## Development Process
|
||||
|
||||
### 1. Feature Development
|
||||
1. Planning
|
||||
- Technical specification
|
||||
- Component design
|
||||
- Database impact
|
||||
- Test strategy
|
||||
|
||||
2. Implementation
|
||||
- Create feature branch
|
||||
- Write tests first
|
||||
- Implement feature
|
||||
- Update documentation
|
||||
|
||||
3. Review
|
||||
- Self-review checklist
|
||||
- Peer code review
|
||||
- Update per feedback
|
||||
- Final verification
|
||||
|
||||
### 2. Testing Requirements
|
||||
|
||||
#### Unit Tests
|
||||
```python
|
||||
# Required for all new code
|
||||
class TestFeature(TestCase):
|
||||
def setUp(self):
|
||||
# Setup test data
|
||||
|
||||
def test_functionality(self):
|
||||
# Test core functionality
|
||||
|
||||
def test_edge_cases(self):
|
||||
# Test edge cases
|
||||
```
|
||||
|
||||
#### Integration Tests
|
||||
- API endpoints
|
||||
- User workflows
|
||||
- System integration
|
||||
- Error handling
|
||||
|
||||
#### Coverage Requirements
|
||||
- Minimum 80% coverage
|
||||
- Critical paths 100%
|
||||
- Edge case handling
|
||||
- Error scenarios
|
||||
|
||||
### 3. Code Quality
|
||||
|
||||
#### Linting
|
||||
- Python: flake8
|
||||
- JavaScript: eslint
|
||||
- CSS: stylelint
|
||||
- Templates: djlint
|
||||
|
||||
#### Type Checking
|
||||
- Python: mypy
|
||||
- JavaScript: TypeScript
|
||||
|
||||
#### Documentation
|
||||
- Code comments
|
||||
- Docstrings
|
||||
- README updates
|
||||
- API documentation
|
||||
|
||||
## Deployment Process
|
||||
|
||||
### 1. Pre-deployment
|
||||
- Version bump
|
||||
- Changelog update
|
||||
- Documentation review
|
||||
- Test verification
|
||||
|
||||
### 2. Staging Deployment
|
||||
- Database migrations
|
||||
- Static file collection
|
||||
- Smoke tests
|
||||
- Performance check
|
||||
|
||||
### 3. Production Deployment
|
||||
- Backup database
|
||||
- Apply migrations
|
||||
- Update static files
|
||||
- Health checks
|
||||
|
||||
### 4. Post-deployment
|
||||
- Monitor errors
|
||||
- Performance metrics
|
||||
- User feedback
|
||||
- Rollback plan
|
||||
|
||||
## Review Process
|
||||
|
||||
### 1. Code Review
|
||||
- Style compliance
|
||||
- Test coverage
|
||||
- Documentation
|
||||
- Performance impact
|
||||
|
||||
### 2. Architecture Review
|
||||
- Design patterns
|
||||
- Scalability
|
||||
- Security
|
||||
- Maintainability
|
||||
|
||||
### 3. Security Review
|
||||
- Authentication
|
||||
- Authorization
|
||||
- Data protection
|
||||
- Input validation
|
||||
|
||||
## Quality Assurance
|
||||
|
||||
### 1. Testing Strategy
|
||||
- Unit testing
|
||||
- Integration testing
|
||||
- End-to-end testing
|
||||
- Performance testing
|
||||
|
||||
### 2. Performance Standards
|
||||
- Page load times
|
||||
- Database queries
|
||||
- API response times
|
||||
- Resource usage
|
||||
|
||||
### 3. Security Standards
|
||||
- Authentication
|
||||
- Authorization
|
||||
- Data encryption
|
||||
- Input validation
|
||||
|
||||
## Monitoring and Maintenance
|
||||
|
||||
### 1. Error Tracking
|
||||
- Exception monitoring
|
||||
- Log analysis
|
||||
- User reports
|
||||
- Performance alerts
|
||||
|
||||
### 2. Performance Monitoring
|
||||
- Response times
|
||||
- Resource usage
|
||||
- Database performance
|
||||
- Cache effectiveness
|
||||
|
||||
### 3. User Feedback
|
||||
- Bug reports
|
||||
- Feature requests
|
||||
- Performance issues
|
||||
- UX feedback
|
||||
@@ -5,27 +5,37 @@
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
/* Base Styles */
|
||||
:root {
|
||||
--loading-gradient: linear-gradient(90deg, var(--tw-gradient-from) 0%, var(--tw-gradient-to) 50%, var(--tw-gradient-from) 100%);
|
||||
}
|
||||
|
||||
/* Responsive Layout */
|
||||
@media (max-width: 768px) {
|
||||
.grid-cols-responsive {
|
||||
@apply grid-cols-1;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
@apply flex-col;
|
||||
}
|
||||
|
||||
.action-buttons > * {
|
||||
@apply w-full justify-center;
|
||||
}
|
||||
}
|
||||
|
||||
/* Form Elements */
|
||||
.form-select {
|
||||
@apply rounded-lg border-gray-700 focus:border-blue-500 focus:ring-2 focus:ring-blue-500 bg-gray-800 text-gray-300 transition-colors duration-200;
|
||||
}
|
||||
|
||||
/* Transitions */
|
||||
/* State Management */
|
||||
[x-cloak] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
@apply transition-all duration-200;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
@apply opacity-0;
|
||||
}
|
||||
|
||||
/* HTMX Loading States */
|
||||
/* Loading States */
|
||||
.htmx-request .htmx-indicator {
|
||||
@apply opacity-100;
|
||||
}
|
||||
@@ -38,31 +48,131 @@
|
||||
@apply opacity-0 transition-opacity duration-200;
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
/* Skeleton Loading Animation */
|
||||
.animate-pulse {
|
||||
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: .5;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-spin {
|
||||
animation: spin 1s linear infinite;
|
||||
/* Transitions */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
@apply transition-all duration-200;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
@apply opacity-0;
|
||||
}
|
||||
|
||||
/* Custom Animations */
|
||||
@keyframes shimmer {
|
||||
100% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-shimmer {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.animate-shimmer::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
transform: translateX(-100%);
|
||||
background-image: var(--loading-gradient);
|
||||
animation: shimmer 2s infinite;
|
||||
content: '';
|
||||
}
|
||||
|
||||
/* Accessibility Enhancements */
|
||||
:focus-visible {
|
||||
@apply outline-none ring-2 ring-blue-500 ring-offset-2 ring-offset-white dark:ring-offset-gray-900;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.animate-shimmer::after {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
.animate-pulse {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Touch Device Optimizations */
|
||||
@media (hover: none) {
|
||||
.hover\:shadow-md {
|
||||
@apply shadow-sm;
|
||||
}
|
||||
|
||||
.action-buttons > * {
|
||||
@apply active:transform active:scale-95;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark Mode Optimizations */
|
||||
.dark .animate-shimmer::after {
|
||||
--tw-gradient-from: rgba(31, 41, 55, 0);
|
||||
--tw-gradient-to: rgba(31, 41, 55, 0.1);
|
||||
}
|
||||
|
||||
/* Error States */
|
||||
.error-shake {
|
||||
animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
10%, 90% { transform: translate3d(-1px, 0, 0); }
|
||||
20%, 80% { transform: translate3d(2px, 0, 0); }
|
||||
30%, 50%, 70% { transform: translate3d(-4px, 0, 0); }
|
||||
40%, 60% { transform: translate3d(4px, 0, 0); }
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container max-w-6xl px-4 py-6 mx-auto">
|
||||
<div id="dashboard-content" class="relative transition-opacity duration-200">
|
||||
<div id="dashboard-content" class="relative transition-all duration-200">
|
||||
{% block moderation_content %}
|
||||
{% include "moderation/partials/dashboard_content.html" %}
|
||||
{% endblock %}
|
||||
|
||||
<div id="loading-indicator"
|
||||
class="absolute inset-0 flex items-center justify-center rounded-lg htmx-indicator bg-gray-900/80">
|
||||
<div class="flex items-center p-6 space-x-4">
|
||||
<div class="w-8 h-8 border-4 border-blue-500 rounded-full animate-spin border-t-transparent"></div>
|
||||
<span class="text-gray-300">Loading...</span>
|
||||
<!-- Loading Skeleton -->
|
||||
<div class="absolute inset-0 htmx-indicator" id="loading-skeleton">
|
||||
{% include "moderation/partials/loading_skeleton.html" %}
|
||||
</div>
|
||||
|
||||
<!-- Error State -->
|
||||
<div class="absolute inset-0 hidden" id="error-state">
|
||||
<div class="flex flex-col items-center justify-center h-full p-6 space-y-4 text-center">
|
||||
<div class="p-4 text-red-500 bg-red-100 rounded-full dark:bg-red-900/40">
|
||||
<i class="text-4xl fas fa-exclamation-circle"></i>
|
||||
</div>
|
||||
<h3 class="text-lg font-medium text-red-600 dark:text-red-400">
|
||||
Something went wrong
|
||||
</h3>
|
||||
<p class="max-w-md text-gray-600 dark:text-gray-400" id="error-message">
|
||||
There was a problem loading the content. Please try again.
|
||||
</p>
|
||||
<button class="px-4 py-2 font-medium text-white transition-all duration-200 bg-red-600 rounded-lg hover:bg-red-500 dark:bg-red-700 dark:hover:bg-red-600"
|
||||
onclick="window.location.reload()">
|
||||
<i class="mr-2 fas fa-sync-alt"></i>
|
||||
Retry
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -71,20 +181,116 @@
|
||||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
// Configure HTMX to include CSRF token in all requests
|
||||
// HTMX Configuration and Enhancements
|
||||
document.body.addEventListener('htmx:configRequest', function(evt) {
|
||||
evt.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
|
||||
});
|
||||
|
||||
// Loading and Error State Management
|
||||
const dashboard = {
|
||||
content: document.getElementById('dashboard-content'),
|
||||
skeleton: document.getElementById('loading-skeleton'),
|
||||
errorState: document.getElementById('error-state'),
|
||||
errorMessage: document.getElementById('error-message'),
|
||||
|
||||
showLoading() {
|
||||
this.content.setAttribute('aria-busy', 'true');
|
||||
this.content.style.opacity = '0';
|
||||
this.errorState.classList.add('hidden');
|
||||
},
|
||||
|
||||
hideLoading() {
|
||||
this.content.setAttribute('aria-busy', 'false');
|
||||
this.content.style.opacity = '1';
|
||||
},
|
||||
|
||||
showError(message) {
|
||||
this.errorState.classList.remove('hidden');
|
||||
this.errorMessage.textContent = message || 'There was a problem loading the content. Please try again.';
|
||||
// Announce error to screen readers
|
||||
this.errorMessage.setAttribute('role', 'alert');
|
||||
}
|
||||
};
|
||||
|
||||
// Enhanced HTMX Event Handlers
|
||||
document.body.addEventListener('htmx:beforeRequest', function(evt) {
|
||||
if (evt.detail.target.id === 'dashboard-content') {
|
||||
evt.detail.target.style.opacity = '0.5';
|
||||
dashboard.showLoading();
|
||||
}
|
||||
});
|
||||
|
||||
document.body.addEventListener('htmx:afterOnLoad', function(evt) {
|
||||
if (evt.detail.target.id === 'dashboard-content') {
|
||||
evt.detail.target.style.opacity = '1';
|
||||
dashboard.hideLoading();
|
||||
// Reset focus for accessibility
|
||||
const firstFocusable = evt.detail.target.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
|
||||
if (firstFocusable) {
|
||||
firstFocusable.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.body.addEventListener('htmx:responseError', function(evt) {
|
||||
if (evt.detail.target.id === 'dashboard-content') {
|
||||
dashboard.showError(evt.detail.error);
|
||||
}
|
||||
});
|
||||
|
||||
// Search Input Debouncing
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function executedFunction(...args) {
|
||||
const later = () => {
|
||||
clearTimeout(timeout);
|
||||
func(...args);
|
||||
};
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
};
|
||||
}
|
||||
|
||||
// Apply debouncing to search inputs
|
||||
document.querySelectorAll('[data-search]').forEach(input => {
|
||||
const originalSearch = () => {
|
||||
htmx.trigger(input, 'input');
|
||||
};
|
||||
const debouncedSearch = debounce(originalSearch, 300);
|
||||
|
||||
input.addEventListener('input', (e) => {
|
||||
e.preventDefault();
|
||||
debouncedSearch();
|
||||
});
|
||||
});
|
||||
|
||||
// Virtual Scrolling for Large Lists
|
||||
const observerOptions = {
|
||||
root: null,
|
||||
rootMargin: '100px',
|
||||
threshold: 0.1
|
||||
};
|
||||
|
||||
const loadMoreContent = (entries, observer) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting && !entry.target.classList.contains('loading')) {
|
||||
entry.target.classList.add('loading');
|
||||
htmx.trigger(entry.target, 'intersect');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const observer = new IntersectionObserver(loadMoreContent, observerOptions);
|
||||
document.querySelectorAll('[data-infinite-scroll]').forEach(el => observer.observe(el));
|
||||
|
||||
// Keyboard Navigation Enhancement
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape') {
|
||||
const openModals = document.querySelectorAll('[x-show="showNotes"]');
|
||||
openModals.forEach(modal => {
|
||||
const alpineData = modal.__x.$data;
|
||||
if (alpineData.showNotes) {
|
||||
alpineData.showNotes = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -56,44 +56,93 @@
|
||||
</div>
|
||||
|
||||
<div class="p-6 bg-white border rounded-lg dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50">
|
||||
<form class="flex flex-wrap items-end gap-4 mb-6"
|
||||
<form class="mb-6"
|
||||
x-data="{ showFilters: false }"
|
||||
hx-get="{% url 'moderation:submission_list' %}"
|
||||
hx-target="#dashboard-content"
|
||||
hx-trigger="change"
|
||||
hx-push-url="true">
|
||||
hx-trigger="change from:select"
|
||||
hx-push-url="true"
|
||||
aria-label="Submission filters">
|
||||
|
||||
<div class="flex-1 min-w-[200px]">
|
||||
<label class="block mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">
|
||||
Submission Type
|
||||
</label>
|
||||
<select name="submission_type" class="w-full px-3 py-2 text-gray-900 bg-white border rounded-lg dark:text-gray-300 dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
<option value="">All Submissions</option>
|
||||
<option value="text" {% if request.GET.submission_type == 'text' %}selected{% endif %}>Text Submissions</option>
|
||||
<option value="photo" {% if request.GET.submission_type == 'photo' %}selected{% endif %}>Photo Submissions</option>
|
||||
</select>
|
||||
</div>
|
||||
<!-- Mobile Filter Toggle -->
|
||||
<button type="button"
|
||||
class="flex items-center w-full gap-2 p-3 mb-4 font-medium text-left text-gray-700 transition-colors duration-200 bg-gray-100 rounded-lg md:hidden dark:text-gray-300 dark:bg-gray-900"
|
||||
@click="showFilters = !showFilters"
|
||||
:aria-expanded="showFilters"
|
||||
aria-controls="filter-controls">
|
||||
<i class="fas" :class="showFilters ? 'fa-chevron-up' : 'fa-chevron-down'"></i>
|
||||
<span>Filter Options</span>
|
||||
<span class="flex items-center ml-auto space-x-1 text-sm text-gray-500 dark:text-gray-400">
|
||||
<span class="active-filters">{{ request.GET|length }} active</span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div class="flex-1 min-w-[200px]">
|
||||
<label class="block mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">
|
||||
Type
|
||||
</label>
|
||||
<select name="type" class="w-full px-3 py-2 text-gray-900 bg-white border rounded-lg dark:text-gray-300 dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
<option value="">All Types</option>
|
||||
<option value="CREATE" {% if request.GET.type == 'CREATE' %}selected{% endif %}>New Submissions</option>
|
||||
<option value="EDIT" {% if request.GET.type == 'EDIT' %}selected{% endif %}>Edit Submissions</option>
|
||||
</select>
|
||||
</div>
|
||||
<!-- Filter Controls -->
|
||||
<div id="filter-controls"
|
||||
class="grid gap-4 transition-all duration-200 md:grid-cols-3"
|
||||
:class="{'hidden md:grid': !showFilters, 'grid': showFilters}"
|
||||
role="group"
|
||||
aria-label="Filter controls">
|
||||
|
||||
<div class="relative">
|
||||
<label id="submission-type-label"
|
||||
class="block mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">
|
||||
Submission Type
|
||||
</label>
|
||||
<select name="submission_type"
|
||||
aria-labelledby="submission-type-label"
|
||||
class="w-full px-3 py-2 text-gray-900 bg-white border rounded-lg dark:text-gray-300 dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
@change="$dispatch('filter-changed')">
|
||||
<option value="">All Submissions</option>
|
||||
<option value="text" {% if request.GET.submission_type == 'text' %}selected{% endif %}>Text Submissions</option>
|
||||
<option value="photo" {% if request.GET.submission_type == 'photo' %}selected{% endif %}>Photo Submissions</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 min-w-[200px]">
|
||||
<label class="block mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">
|
||||
Content Type
|
||||
</label>
|
||||
<select name="content_type" class="w-full px-3 py-2 text-gray-900 bg-white border rounded-lg dark:text-gray-300 dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
<option value="">All Content</option>
|
||||
<option value="park" {% if request.GET.content_type == 'park' %}selected{% endif %}>Parks</option>
|
||||
<option value="ride" {% if request.GET.content_type == 'ride' %}selected{% endif %}>Rides</option>
|
||||
<option value="company" {% if request.GET.content_type == 'company' %}selected{% endif %}>Companies</option>
|
||||
</select>
|
||||
<div class="relative">
|
||||
<label id="type-label"
|
||||
class="block mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">
|
||||
Type
|
||||
</label>
|
||||
<select name="type"
|
||||
aria-labelledby="type-label"
|
||||
class="w-full px-3 py-2 text-gray-900 bg-white border rounded-lg dark:text-gray-300 dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
@change="$dispatch('filter-changed')">
|
||||
<option value="">All Types</option>
|
||||
<option value="CREATE" {% if request.GET.type == 'CREATE' %}selected{% endif %}>New Submissions</option>
|
||||
<option value="EDIT" {% if request.GET.type == 'EDIT' %}selected{% endif %}>Edit Submissions</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="relative">
|
||||
<label id="content-type-label"
|
||||
class="block mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">
|
||||
Content Type
|
||||
</label>
|
||||
<select name="content_type"
|
||||
aria-labelledby="content-type-label"
|
||||
class="w-full px-3 py-2 text-gray-900 bg-white border rounded-lg dark:text-gray-300 dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
@change="$dispatch('filter-changed')">
|
||||
<option value="">All Content</option>
|
||||
<option value="park" {% if request.GET.content_type == 'park' %}selected{% endif %}>Parks</option>
|
||||
<option value="ride" {% if request.GET.content_type == 'ride' %}selected{% endif %}>Rides</option>
|
||||
<option value="company" {% if request.GET.content_type == 'company' %}selected{% endif %}>Companies</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Applied Filters Summary -->
|
||||
<div class="hidden pt-2 md:col-span-3 md:block">
|
||||
<div class="flex flex-wrap gap-2"
|
||||
x-show="$store.filters.hasActiveFilters"
|
||||
x-cloak>
|
||||
<template x-for="filter in $store.filters.active" :key="filter.name">
|
||||
<span class="inline-flex items-center px-2 py-1 text-sm bg-blue-100 rounded dark:bg-blue-900/40">
|
||||
<span class="mr-1 text-blue-700 dark:text-blue-300" x-text="filter.label + ':'"></span>
|
||||
<span class="font-medium text-blue-900 dark:text-blue-100" x-text="filter.value"></span>
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
129
templates/moderation/partials/filters_store.html
Normal file
129
templates/moderation/partials/filters_store.html
Normal file
@@ -0,0 +1,129 @@
|
||||
{% comment %}
|
||||
This template contains the Alpine.js store for managing filter state in the moderation dashboard
|
||||
{% endcomment %}
|
||||
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.store('filters', {
|
||||
active: [],
|
||||
|
||||
init() {
|
||||
this.updateActiveFilters();
|
||||
|
||||
// Listen for filter changes
|
||||
window.addEventListener('filter-changed', () => {
|
||||
this.updateActiveFilters();
|
||||
});
|
||||
},
|
||||
|
||||
updateActiveFilters() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
this.active = [];
|
||||
|
||||
// Submission Type
|
||||
if (urlParams.has('submission_type')) {
|
||||
this.active.push({
|
||||
name: 'submission_type',
|
||||
label: 'Submission',
|
||||
value: this.getSubmissionTypeLabel(urlParams.get('submission_type'))
|
||||
});
|
||||
}
|
||||
|
||||
// Type
|
||||
if (urlParams.has('type')) {
|
||||
this.active.push({
|
||||
name: 'type',
|
||||
label: 'Type',
|
||||
value: this.getTypeLabel(urlParams.get('type'))
|
||||
});
|
||||
}
|
||||
|
||||
// Content Type
|
||||
if (urlParams.has('content_type')) {
|
||||
this.active.push({
|
||||
name: 'content_type',
|
||||
label: 'Content',
|
||||
value: this.getContentTypeLabel(urlParams.get('content_type'))
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
getSubmissionTypeLabel(value) {
|
||||
const labels = {
|
||||
'text': 'Text',
|
||||
'photo': 'Photo'
|
||||
};
|
||||
return labels[value] || value;
|
||||
},
|
||||
|
||||
getTypeLabel(value) {
|
||||
const labels = {
|
||||
'CREATE': 'New',
|
||||
'EDIT': 'Edit'
|
||||
};
|
||||
return labels[value] || value;
|
||||
},
|
||||
|
||||
getContentTypeLabel(value) {
|
||||
const labels = {
|
||||
'park': 'Parks',
|
||||
'ride': 'Rides',
|
||||
'company': 'Companies'
|
||||
};
|
||||
return labels[value] || value;
|
||||
},
|
||||
|
||||
get hasActiveFilters() {
|
||||
return this.active.length > 0;
|
||||
},
|
||||
|
||||
clear() {
|
||||
const form = document.querySelector('form[hx-get]');
|
||||
if (form) {
|
||||
form.querySelectorAll('select').forEach(select => {
|
||||
select.value = '';
|
||||
});
|
||||
form.dispatchEvent(new Event('change'));
|
||||
}
|
||||
},
|
||||
|
||||
// Accessibility Helpers
|
||||
announceFilterChange() {
|
||||
const message = this.hasActiveFilters
|
||||
? `Applied filters: ${this.active.map(f => f.label + ': ' + f.value).join(', ')}`
|
||||
: 'All filters cleared';
|
||||
|
||||
const announcement = document.createElement('div');
|
||||
announcement.setAttribute('role', 'status');
|
||||
announcement.setAttribute('aria-live', 'polite');
|
||||
announcement.className = 'sr-only';
|
||||
announcement.textContent = message;
|
||||
|
||||
document.body.appendChild(announcement);
|
||||
setTimeout(() => announcement.remove(), 1000);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Watch for filter changes and update URL params
|
||||
document.addEventListener('filter-changed', (e) => {
|
||||
const form = e.target.closest('form');
|
||||
if (!form) return;
|
||||
|
||||
const formData = new FormData(form);
|
||||
const params = new URLSearchParams();
|
||||
|
||||
for (let [key, value] of formData.entries()) {
|
||||
if (value) {
|
||||
params.append(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Update URL without page reload
|
||||
const newUrl = window.location.pathname + (params.toString() ? '?' + params.toString() : '');
|
||||
window.history.pushState({}, '', newUrl);
|
||||
|
||||
// Announce changes for screen readers
|
||||
Alpine.store('filters').announceFilterChange();
|
||||
});
|
||||
</script>
|
||||
66
templates/moderation/partials/loading_skeleton.html
Normal file
66
templates/moderation/partials/loading_skeleton.html
Normal file
@@ -0,0 +1,66 @@
|
||||
{% load static %}
|
||||
|
||||
<div class="animate-pulse">
|
||||
<!-- Filter Bar Skeleton -->
|
||||
<div class="flex items-center justify-between p-4 mb-6 bg-white border rounded-lg dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50">
|
||||
<div class="flex items-center space-x-4">
|
||||
{% for i in "1234" %}
|
||||
<div class="w-24 h-10 bg-gray-200 rounded-lg dark:bg-gray-700"></div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="w-24 h-10 bg-gray-200 rounded-lg dark:bg-gray-700"></div>
|
||||
</div>
|
||||
|
||||
<!-- Filter Form Skeleton -->
|
||||
<div class="p-6 mb-6 bg-white border rounded-lg dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50">
|
||||
<div class="flex flex-wrap items-end gap-4">
|
||||
{% for i in "123" %}
|
||||
<div class="flex-1 min-w-[200px] space-y-2">
|
||||
<div class="w-24 h-4 bg-gray-200 rounded dark:bg-gray-700"></div>
|
||||
<div class="w-full h-10 bg-gray-200 rounded-lg dark:bg-gray-700"></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Submission List Skeleton -->
|
||||
{% for i in "123" %}
|
||||
<div class="p-6 mb-4 bg-white border rounded-lg dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50">
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-3">
|
||||
<!-- Left Column -->
|
||||
<div class="space-y-4 md:col-span-1">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-24 h-6 bg-gray-200 rounded-lg dark:bg-gray-700"></div>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
{% for i in "1234" %}
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-5 h-5 bg-gray-200 rounded dark:bg-gray-700"></div>
|
||||
<div class="w-32 h-4 bg-gray-200 rounded dark:bg-gray-700"></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Column -->
|
||||
<div class="md:col-span-2">
|
||||
{% for i in "12" %}
|
||||
<div class="p-4 mb-4 bg-gray-100 border rounded-lg dark:bg-gray-900 border-gray-200/50 dark:border-gray-700/50">
|
||||
<div class="w-24 h-4 mb-2 bg-gray-200 rounded dark:bg-gray-700"></div>
|
||||
<div class="w-full h-4 bg-gray-200 rounded dark:bg-gray-700"></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="grid grid-cols-1 gap-3 mt-4 md:grid-cols-2">
|
||||
{% for i in "1234" %}
|
||||
<div class="p-4 bg-gray-100 border rounded-lg dark:bg-gray-900 border-gray-200/50 dark:border-gray-700/50">
|
||||
<div class="w-24 h-4 mb-2 bg-gray-200 rounded dark:bg-gray-700"></div>
|
||||
<div class="w-full h-4 bg-gray-200 rounded dark:bg-gray-700"></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@@ -162,7 +162,7 @@ AUTHENTICATION_BACKENDS = [
|
||||
SITE_ID = 1
|
||||
ACCOUNT_EMAIL_REQUIRED = True
|
||||
ACCOUNT_USERNAME_REQUIRED = True
|
||||
ACCOUNT_AUTHENTICATION_METHOD = "username_email"
|
||||
ACCOUNT_LOGIN_METHODS = {'email', 'username'}
|
||||
ACCOUNT_EMAIL_VERIFICATION = "optional"
|
||||
LOGIN_REDIRECT_URL = "/"
|
||||
ACCOUNT_LOGOUT_REDIRECT_URL = "/"
|
||||
|
||||
Reference in New Issue
Block a user