Files
thrillwiki_django_no_react/docs/ux/cta-guidelines.md

424 lines
8.4 KiB
Markdown

# Call-to-Action (CTA) Guidelines
This document outlines the standardized patterns for buttons, links, and action elements in ThrillWiki.
## Button Hierarchy
### Primary Actions
Use for the main action on a page or in a section:
```html
<button class="btn btn-primary">Save Park</button>
<a href="/create/" class="btn btn-primary">Create New</a>
```
**When to use:**
- Form submissions
- Main page actions
- Completing a flow
### Secondary Actions
Use for important but non-primary actions:
```html
<button class="btn btn-outline">Preview</button>
<button class="btn btn-secondary">Save Draft</button>
```
**When to use:**
- Alternative actions
- Non-destructive secondary options
- Cancel with importance
### Tertiary Actions
Use for low-emphasis actions:
```html
<button class="btn btn-ghost">Cancel</button>
<a href="/back/" class="btn btn-link">Go Back</a>
```
**When to use:**
- Cancel buttons
- Navigation links
- Dismissive actions
### Destructive Actions
Use for actions that delete or remove data:
```html
<button class="btn btn-destructive">Delete Park</button>
```
**When to use:**
- Delete operations
- Remove actions
- Destructive confirmations
## Button Sizes
```html
<!-- Small - for compact UIs -->
<button class="btn btn-primary btn-sm">Small</button>
<!-- Default -->
<button class="btn btn-primary">Default</button>
<!-- Large - for prominent CTAs -->
<button class="btn btn-primary btn-lg">Large</button>
```
## Button States
### Loading State
```html
<button class="btn btn-primary" disabled>
<i class="fas fa-spinner fa-spin mr-2"></i>
Saving...
</button>
```
### Disabled State
```html
<button class="btn btn-primary" disabled>
Submit
</button>
```
### With Icon
```html
<button class="btn btn-primary">
<i class="fas fa-plus mr-2"></i>
Add Park
</button>
<button class="btn btn-outline">
Download
<i class="fas fa-download ml-2"></i>
</button>
```
## Action Bar Component
Use the action bar for consistent button placement:
```django
{% include 'components/ui/action_bar.html' with
primary_action_text='Save Changes'
primary_action_icon='fas fa-save'
secondary_action_text='Preview'
tertiary_action_text='Cancel'
tertiary_action_url='/parks/'
%}
```
### Alignment Options
```django
{# Right-aligned (default) #}
{% include 'components/ui/action_bar.html' with align='right' ... %}
{# Left-aligned #}
{% include 'components/ui/action_bar.html' with align='left' ... %}
{# Space-between (cancel left, actions right) #}
{% include 'components/ui/action_bar.html' with align='between' ... %}
{# Center-aligned #}
{% include 'components/ui/action_bar.html' with align='center' ... %}
```
## Placement Guidelines
### Page Headers
Primary CTA in page header, aligned right:
```django
{% include 'components/layout/page_header.html' with
title='Parks'
primary_action_url='/parks/create/'
primary_action_text='Add Park'
primary_action_icon='fas fa-plus'
%}
```
### Card Actions
Actions in card footer, right-aligned:
```html
<div class="card">
<div class="card-body">
<!-- Content -->
</div>
<div class="card-footer flex justify-end gap-2">
<button class="btn btn-ghost btn-sm">Cancel</button>
<button class="btn btn-primary btn-sm">Save</button>
</div>
</div>
```
### Form Actions
Form buttons at bottom, with cancel on left or right based on flow:
```html
<!-- Standard form (cancel left, submit right) -->
<div class="flex justify-between mt-6">
<a href="/cancel/" class="btn btn-ghost">Cancel</a>
<button type="submit" class="btn btn-primary">Save</button>
</div>
<!-- Simple form (all right-aligned) -->
<div class="flex justify-end gap-3 mt-6">
<button type="button" class="btn btn-ghost">Cancel</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
```
### Modal Actions
Actions in modal footer, right-aligned:
```html
<div class="modal-footer">
<button @click="showModal = false" class="btn btn-ghost">
Cancel
</button>
<button class="btn btn-primary">
Confirm
</button>
</div>
```
### Inline Actions
For table rows or list items:
```html
<div class="flex items-center gap-2">
<button class="btn btn-ghost btn-sm">
<i class="fas fa-edit"></i>
</button>
<button class="btn btn-ghost btn-sm text-destructive">
<i class="fas fa-trash"></i>
</button>
</div>
```
## Link vs Button
### Use Links For:
- Navigation to other pages
- Opening in new tabs
- Bookmarkable destinations
```html
<a href="/parks/123/" class="btn btn-primary">View Park</a>
```
### Use Buttons For:
- Form submissions
- JavaScript actions
- State changes
- Toggles
```html
<button type="submit" class="btn btn-primary">Save</button>
<button @click="showModal = true" class="btn btn-outline">Open Modal</button>
```
## Icon Guidelines
### Icon Position
- **Left icon**: For actions (Add, Create, Save)
- **Right icon**: For navigation (Next, Go, External link)
```html
<!-- Action with left icon -->
<button class="btn btn-primary">
<i class="fas fa-plus mr-2"></i>
Add Park
</button>
<!-- Navigation with right icon -->
<a href="/next/" class="btn btn-outline">
Next Step
<i class="fas fa-arrow-right ml-2"></i>
</a>
```
### Common Icon Mappings
| Action | Icon |
|--------|------|
| Create/Add | `fa-plus` |
| Edit | `fa-edit` or `fa-pen` |
| Delete | `fa-trash` |
| Save | `fa-save` |
| Cancel | `fa-times` |
| Search | `fa-search` |
| Filter | `fa-filter` |
| Download | `fa-download` |
| Upload | `fa-upload` |
| Settings | `fa-cog` |
| Back | `fa-arrow-left` |
| Next | `fa-arrow-right` |
| External Link | `fa-external-link-alt` |
## Confirmation Patterns
### Inline Confirmation (Low Risk)
```html
<button hx-delete="/items/123/"
hx-confirm="Delete this item?">
Delete
</button>
```
### Modal Confirmation (High Risk)
```django
<button @click="showDeleteModal = true" class="btn btn-destructive">
Delete Park
</button>
{% include 'components/modals/modal_confirm.html' with
modal_id='delete-confirm'
show_var='showDeleteModal'
title='Delete Park'
message='This will permanently delete the park and all associated data. This action cannot be undone.'
confirm_text='Delete'
confirm_variant='destructive'
confirm_hx_delete='/parks/123/'
%}
```
## Responsive Behavior
### Mobile Stacking
Buttons stack vertically on mobile:
```html
<div class="flex flex-col sm:flex-row gap-3">
<button class="btn btn-ghost order-2 sm:order-1">Cancel</button>
<button class="btn btn-primary order-1 sm:order-2">Save</button>
</div>
```
### Icon-Only on Mobile
```html
<button class="btn btn-outline">
<i class="fas fa-filter"></i>
<span class="hidden sm:inline ml-2">Filter</span>
</button>
```
### Full-Width on Mobile
```html
<button class="btn btn-primary w-full sm:w-auto">
Save Changes
</button>
```
## Accessibility
### Button Labels
Always provide accessible labels:
```html
<!-- Icon-only buttons need aria-label -->
<button class="btn btn-ghost" aria-label="Edit park">
<i class="fas fa-edit" aria-hidden="true"></i>
</button>
<!-- Or use visually hidden text -->
<button class="btn btn-ghost">
<i class="fas fa-edit" aria-hidden="true"></i>
<span class="sr-only">Edit park</span>
</button>
```
### Focus States
All buttons must have visible focus states:
```css
.btn:focus {
outline: none;
ring: 2px;
ring-offset: 2px;
ring-color: var(--ring);
}
```
### Keyboard Navigation
Ensure buttons are keyboard accessible:
```html
<!-- Use native button elements -->
<button class="btn btn-primary">Click Me</button>
<!-- If using div/span, add role and tabindex -->
<div role="button" tabindex="0" class="btn btn-primary"
@keydown.enter="handleClick"
@keydown.space.prevent="handleClick">
Click Me
</div>
```
## HTMX Integration
### Loading Indicators
Show loading state during requests:
```html
<button hx-post="/save/"
hx-indicator="this"
class="btn btn-primary">
<span class="htmx-indicator hidden">
<i class="fas fa-spinner fa-spin mr-2"></i>
</span>
Save
</button>
```
### Disable During Request
```html
<button hx-post="/save/"
hx-disabled-elt="this"
class="btn btn-primary">
Save
</button>
```
### Success Feedback
```python
# In view
from apps.core.htmx_utils import htmx_success
def save_item(request):
# ... save logic ...
return htmx_success('Item saved successfully!')
```