mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-23 16:11:08 -05:00
424 lines
8.4 KiB
Markdown
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!')
|
|
```
|