# 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
```
#### 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
```
#### 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
```
### 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
Edit Park
```
#### 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