Files
thrillwiki_django_no_react/backend/templates/components/ui/input.html

163 lines
7.2 KiB
HTML

{% comment %}
Input Component - Unified Django Template Version of shadcn/ui Input
A versatile input component that supports both Django form fields and standalone inputs.
Compatible with HTMX and Alpine.js for dynamic behavior.
Usage Examples:
Standalone input:
{% include 'components/ui/input.html' with type='text' name='email' placeholder='Enter email' %}
With Django form field:
{% include 'components/ui/input.html' with field=form.email label='Email Address' %}
With HTMX validation:
{% include 'components/ui/input.html' with name='username' hx_post='/validate' hx_trigger='blur' %}
With Alpine.js binding:
{% include 'components/ui/input.html' with name='search' x_model='query' %}
Textarea mode:
{% include 'components/ui/input.html' with type='textarea' name='message' rows='4' %}
Parameters:
Standalone Mode:
- type: Input type (text, email, password, number, etc.) or 'textarea' (default: 'text')
- name: Input name attribute
- id: Input ID (auto-generated from name if not provided)
- placeholder: Placeholder text
- value: Initial value
- label: Label text
- help_text: Help text displayed below the input
- error: Error message to display
- required: Boolean for required field
- disabled: Boolean to disable the input
- readonly: Boolean for readonly input
- autocomplete: Autocomplete attribute value
- rows: Number of rows for textarea
- class: Additional CSS classes for the input
Django Form Field Mode:
- field: Django form field object
- label: Override field label
- placeholder: Override field placeholder
- help_text: Override field help text
HTMX Attributes:
- hx_get, hx_post, hx_target, hx_swap, hx_trigger, hx_include: HTMX attributes
Alpine.js Attributes:
- x_model: Two-way binding
- x_on: Event handlers (as string, e.g., "@input=...")
- x_data: Alpine data
Other:
- attrs: Additional HTML attributes as string
- aria_describedby: ID of element describing this input
- aria_invalid: Boolean for invalid state
{% endcomment %}
{% load widget_tweaks %}
{% if field %}
{# Django Form Field Mode #}
<div class="space-y-2">
{% if label or field.label %}
<label for="{{ field.id_for_label }}"
class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
{{ label|default:field.label }}
{% if field.field.required %}<span class="text-destructive">*</span>{% endif %}
</label>
{% endif %}
{% render_field field class+="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" placeholder=placeholder|default:field.label aria-describedby=field.id_for_label|add:"-description" aria-invalid=field.errors|yesno:"true,false" %}
{% if help_text or field.help_text %}
<p id="{{ field.id_for_label }}-description" class="text-sm text-muted-foreground">
{{ help_text|default:field.help_text }}
</p>
{% endif %}
{% if field.errors %}
<p class="text-sm font-medium text-destructive" role="alert">
{{ field.errors.0 }}
</p>
{% endif %}
</div>
{% else %}
{# Standalone Mode #}
{% with input_id=id|default:name %}
<div class="space-y-2">
{% if label %}
<label for="{{ input_id }}"
class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
{{ label }}
{% if required %}<span class="text-destructive">*</span>{% endif %}
</label>
{% endif %}
{% if type == 'textarea' %}
<textarea
{% if name %}name="{{ name }}"{% endif %}
{% if input_id %}id="{{ input_id }}"{% endif %}
class="flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 {{ class|default:'' }}"
{% if placeholder %}placeholder="{{ placeholder }}"{% endif %}
{% if rows %}rows="{{ rows }}"{% endif %}
{% if required %}required{% endif %}
{% if disabled %}disabled{% endif %}
{% if readonly %}readonly{% endif %}
{% if aria_describedby %}aria-describedby="{{ aria_describedby }}"{% elif help_text %}aria-describedby="{{ input_id }}-description"{% endif %}
{% if aria_invalid or error %}aria-invalid="true"{% endif %}
{% if x_model %}x-model="{{ x_model }}"{% endif %}
{% if x_on %}{{ x_on }}{% endif %}
{% if x_data %}x-data="{{ x_data }}"{% endif %}
{% if hx_get %}hx-get="{{ hx_get }}"{% endif %}
{% if hx_post %}hx-post="{{ hx_post }}"{% endif %}
{% if hx_target %}hx-target="{{ hx_target }}"{% endif %}
{% if hx_trigger %}hx-trigger="{{ hx_trigger }}"{% endif %}
{% if hx_swap %}hx-swap="{{ hx_swap }}"{% endif %}
{% if hx_include %}hx-include="{{ hx_include }}"{% endif %}
{{ attrs|default:'' }}>{{ value|default:'' }}</textarea>
{% else %}
<input
type="{{ type|default:'text' }}"
{% if name %}name="{{ name }}"{% endif %}
{% if input_id %}id="{{ input_id }}"{% endif %}
class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 {{ class|default:'' }}"
{% if placeholder %}placeholder="{{ placeholder }}"{% endif %}
{% if value %}value="{{ value }}"{% endif %}
{% if required %}required{% endif %}
{% if disabled %}disabled{% endif %}
{% if readonly %}readonly{% endif %}
{% if autocomplete %}autocomplete="{{ autocomplete }}"{% endif %}
{% if aria_describedby %}aria-describedby="{{ aria_describedby }}"{% elif help_text %}aria-describedby="{{ input_id }}-description"{% endif %}
{% if aria_invalid or error %}aria-invalid="true"{% endif %}
{% if x_model %}x-model="{{ x_model }}"{% endif %}
{% if x_on %}{{ x_on }}{% endif %}
{% if x_data %}x-data="{{ x_data }}"{% endif %}
{% if hx_get %}hx-get="{{ hx_get }}"{% endif %}
{% if hx_post %}hx-post="{{ hx_post }}"{% endif %}
{% if hx_target %}hx-target="{{ hx_target }}"{% endif %}
{% if hx_trigger %}hx-trigger="{{ hx_trigger }}"{% endif %}
{% if hx_swap %}hx-swap="{{ hx_swap }}"{% endif %}
{% if hx_include %}hx-include="{{ hx_include }}"{% endif %}
{{ attrs|default:'' }}
/>
{% endif %}
{% if help_text %}
<p id="{{ input_id }}-description" class="text-sm text-muted-foreground">
{{ help_text }}
</p>
{% endif %}
{% if error %}
<p class="text-sm font-medium text-destructive" role="alert">
{{ error }}
</p>
{% endif %}
</div>
{% endwith %}
{% endif %}