{% from "admin/components/ui/combobox.html" import combobox %} {% from "admin/components/ui/switch.html" import switch_control %} {# Form/FormItem, ported from shadcn/ui: every branch below renders the same label + control + description + error unit, with the wrapper classes from ui('field', ...) so a custom field lines up with the generated ones for free. Controls that must survive a JS-free POST stay native elements styled to match shadcn -- checkbox and -- rather than shadcn's Radix-backed versions. The Alpine-driven ports are the relation combobox and the calendar popover. `with context` so the combobox branch can read `base_path` for its /lookup URL without every call site passing it through. #} {% from "admin/components/icons.html" import icon %} {% from "admin/components/ui/calendar.html" import date_picker %} {% from "admin/components/ui/select.html" import select %} {% from "admin/components/ui/multi-select.html" import multi_select %} {# `key` keeps a control's element ids unique when the same field renders more than once on a page, as it does in every row of an inline. #} {% macro render_form_input(field, value, errors, relation=none, readonly_field=false, key="") %} {% set input_types = { "integer": "number", "decimal": "number", "email": "email", "url": "url", "image": "url", "datetime": "datetime-local", "password": "password", } %} {# A boolean renders as a switch on the same row as its name: a toggle reads as a setting, and a setting's name belongs beside it. Every other type keeps the label-above-control layout. #} {% set inline = field.field_type == "boolean" and not readonly_field %}
{{ _(field.help_text) }}
{% endif %} {% for error in errors or [] %}{% endfor %} {% endif %} {% if not inline %}{{ shown if shown else "—" | safe }}
{% elif field.field_type == "text" %} {% elif field.field_type == "date" %} {# DatePicker: a native date input (which already posts YYYY-MM-DD with no JS and gets the platform picker on mobile) plus the shadcn Calendar port in a popover beside it. See components/ui/calendar.html. #} {{ date_picker(field.name, value|form_value(field.field_type), field.required, field.disabled) }} {% elif field.field_type == "enum" %} {% set enum_options = namespace(pairs=[]) %} {% for choice in field.choices %}{% set enum_options.pairs = enum_options.pairs + [(choice, choice)] %}{% endfor %} {{ select(field.name, enum_options.pairs, selected=value, placeholder=_("Select…"), disabled=field.disabled) }} {% elif field.field_type in ("foreignkey", "onetoone") and relation and relation.autocomplete %} {{ combobox(name=field.name, id="combobox-results-" ~ (key ~ "-" if key else "") ~ field.name, selected_pk=relation.selected_pk, selected_label=relation.selected_label, lookup_url=base_path ~ "/" ~ relation.lookup_target ~ "/lookup", placeholder=_('Search…'), disabled=field.disabled) }} {% elif field.field_type in ("foreignkey", "onetoone") %} {{ select(field.name, relation.options if relation else [], selected=(relation.selected_pk if relation else none), placeholder="—", disabled=field.disabled) }} {% elif field.field_type == "manytomany" %} {% set m2m_options = namespace(pairs=[]) %} {% for pk, label in (relation.options if relation else []) %} {% set m2m_options.pairs = m2m_options.pairs + [(pk, label, relation and pk in relation.selected_pks)] %} {% endfor %} {{ multi_select(field.name, m2m_options.pairs, placeholder=_("Select…"), disabled=field.disabled) }} {% else %} {% endif %}{{ _(field.help_text) }}
{% endif %} {% for error in errors or [] %} {% endfor %} {% endif %}