# Migration Guide This guide helps migrate existing templates to use the new standardized UX patterns. ## Overview The ThrillWiki UX standardization introduces: 1. **Breadcrumb system** with Schema.org support 2. **Skeleton screens** for loading states 3. **Standardized form validation** with HTMX 4. **Toast notifications** with action support 5. **Page headers** with consistent layout 6. **Action bars** for button placement 7. **Enhanced modals** with focus trapping 8. **HTMX response utilities** for views ## Step-by-Step Migration ### Step 1: Update Base Template Usage Ensure your templates extend the base template correctly: ```django {% extends 'base/base.html' %} {% block title %}Your Page Title{% endblock %} {% block content %} {% endblock %} ``` ### Step 2: Add Breadcrumbs #### In Your View ```python from apps.core.utils import BreadcrumbBuilder def your_view(request): request.breadcrumbs = ( BreadcrumbBuilder() .add_home() .add('Section', '/section/') .add_current('Current Page') .build() ) return render(request, 'your_template.html') ``` #### In Your Template The breadcrumbs are automatically rendered if you're using the base template. If you need to place them elsewhere: ```django {% include 'components/navigation/breadcrumbs.html' %} ``` ### Step 3: Replace Page Headers #### Before ```html ``` #### After ```django {% include 'components/layout/page_header.html' with title='Parks' subtitle='Browse theme parks worldwide' primary_action_url='/parks/create/' primary_action_text='Add Park' primary_action_icon='fas fa-plus' %} ``` ### Step 4: Update Form Fields #### Before ```html
{{ form.name }} {% if form.name.errors %} {{ form.name.errors.0 }} {% endif %}
``` #### After ```django {% include 'forms/partials/form_field.html' with field=form.name %} ``` For multiple fields with consistent styling: ```django {% for field in form %} {% include 'forms/partials/form_field.html' with field=field %} {% endfor %} ``` ### Step 5: Update Form Actions #### Before ```html
Cancel
``` #### After ```django {% include 'forms/partials/form_actions.html' with submit_text='Save Park' cancel_url='/parks/' %} ``` Or use the action bar for more options: ```django {% include 'components/ui/action_bar.html' with align='between' primary_action_text='Save' tertiary_action_text='Cancel' tertiary_action_url='/parks/' %} ``` ### Step 6: Add Loading States #### For Page Sections ```django
{% include 'components/skeletons/card_grid_skeleton.html' with cards=6 %}
``` #### For Forms ```django
{% csrf_token %}
{% include 'htmx/components/loading_indicator.html' with text='Saving...' %}
``` ### Step 7: Update Toast Messages #### Before (Django Messages) ```python from django.contrib import messages def your_view(request): messages.success(request, 'Park saved!') return redirect('parks:list') ``` #### After (HTMX Response) ```python from apps.core.htmx_utils import htmx_success def your_view(request): # For HTMX requests if request.headers.get('HX-Request'): return htmx_success('Park saved!') # For regular requests, still use messages messages.success(request, 'Park saved!') return redirect('parks:list') ``` ### Step 8: Update Modals #### Before ```html ``` #### After ```django
{% include 'components/modals/modal_base.html' with modal_id='edit-modal' show_var='showEditModal' title='Edit Park' size='lg' %}
``` For confirmation dialogs: ```django {% include 'components/modals/modal_confirm.html' with modal_id='delete-confirm' show_var='showDeleteModal' title='Delete Park' message='Are you sure? This cannot be undone.' confirm_text='Delete' confirm_variant='destructive' confirm_hx_delete='/parks/123/' %} ``` ### Step 9: Update HTMX Views #### Before ```python from django.http import HttpResponse import json def create_park(request): park = Park.objects.create(**form.cleaned_data) response = HttpResponse('') response['HX-Trigger'] = json.dumps({ 'showMessage': {'message': 'Park created!'} }) return response ``` #### After ```python from apps.core.htmx_utils import htmx_success, htmx_error, htmx_modal_close def create_park(request): form = ParkForm(request.POST) if not form.is_valid(): return htmx_error('Validation failed', status=422) park = form.save() # Simple success return htmx_success(f'{park.name} created!') # Or close modal and refresh list return htmx_modal_close( message=f'{park.name} created!', refresh_target='#parks-list' ) ``` ### Step 10: Add Page Meta #### In Your View ```python from apps.core.utils import build_meta_context def park_detail(request, slug): park = get_object_or_404(Park, slug=slug) request.page_meta = build_meta_context( title=park.name, description=park.description, instance=park, request=request, ) return render(request, 'parks/detail.html', {'park': park}) ``` The meta tags are automatically rendered in the base template. ## Component Replacements | Old Pattern | New Component | |-------------|---------------| | Custom page header | `components/layout/page_header.html` | | Form field div | `forms/partials/form_field.html` | | Form buttons | `forms/partials/form_actions.html` or `components/ui/action_bar.html` | | Loading spinner | `htmx/components/loading_indicator.html` | | Placeholder content | `components/skeletons/*.html` | | Custom modal | `components/modals/modal_base.html` | | Confirm dialog | `components/modals/modal_confirm.html` | | Custom breadcrumbs | `components/navigation/breadcrumbs.html` | | Status labels | `components/status_badge.html` | ## View Helper Replacements | Old Pattern | New Helper | |-------------|------------| | `HttpResponse + HX-Trigger` | `htmx_success()` / `htmx_error()` | | `HttpResponse + HX-Redirect` | `htmx_redirect()` | | Custom modal close | `htmx_modal_close()` | | Inline validation | `htmx_validation_response()` | | Check HX-Request header | `is_htmx_request()` | ## Common Issues ### Issue: Breadcrumbs Not Showing 1. Ensure context processor is added to settings: ```python TEMPLATES = [{ 'OPTIONS': { 'context_processors': [ # ... 'apps.core.context_processors.breadcrumbs', ], }, }] ``` 2. Ensure you set `request.breadcrumbs` in your view. ### Issue: Toast Not Appearing 1. Ensure toast container is in base template: ```django {% include 'components/ui/toast-container.html' %} ``` 2. Ensure Alpine.js is loaded and toast store is initialized. 3. For HTMX responses, use the helper functions: ```python return htmx_success('Message here') ``` ### Issue: Modal Not Closing 1. Ensure you're using the correct `show_var`: ```django
{% include 'components/modals/modal_base.html' with show_var='showModal' %}
``` 2. For HTMX responses, use: ```python return htmx_modal_close(message='Done!') ``` ### Issue: Form Validation Not Working 1. Ensure HTMX attributes are correct: ```html
``` 2. Return proper status code on errors: ```python if not form.is_valid(): return render(request, 'form.html', {'form': form}, status=422) ``` ### Issue: Skeleton Not Matching Content Adjust skeleton parameters to match your content: ```django {# For a 3-column grid with 9 cards #} {% include 'components/skeletons/card_grid_skeleton.html' with cards=9 cols=3 %} {# For a table with checkboxes #} {% include 'components/skeletons/table_skeleton.html' with rows=10 columns=5 show_checkbox=True %} ``` ## Testing Migrations After migrating a template: 1. **Visual Check**: Ensure layout matches design 2. **Functionality**: Test all interactive elements 3. **Accessibility**: Test keyboard navigation and screen readers 4. **Responsive**: Check on mobile, tablet, and desktop 5. **Loading States**: Verify skeletons and indicators work 6. **Error States**: Test form validation and error messages 7. **Success States**: Verify toast notifications appear ## Rollback If issues arise, components are designed to be backwards compatible. You can temporarily revert to old patterns while debugging: ```django {% comment %} {% include 'components/layout/page_header.html' with title='Parks' %} {% endcomment %} ```