{# The parts every page is built from (docs/UI.md, section 7). A page has
no markup of its own for a button, a tag, a field, a card header, a
pager or a filter bar. #}
{% macro empty(text) %}
{{ text }}
{% endmacro %}
{# An icon of the sprite, static/img/icons.svg (docs/UI.md 7), by its
name in Bootstrap Icons. Without ``label`` a word or the control
around it says what it is, so it is hidden from screen readers. With
``label`` it stands alone: read out, and shown as a tooltip. #}
{% macro icon(name, label=None) %}{{ _svg(name, label) }}{% endmacro %}
{% macro _svg(name, label=None) %}{% if label %}{% else %}{% endif %}{% endmacro %}
{# The inside of a button or link with an icon: the word beside it, or
with ``alone`` the icon by itself and the word as its tooltip. ``word``
brings the word back where no tooltip shows, on a touch screen or in
a narrow window, for an icon that is not plain on its own. #}
{% macro _face(name, label, alone=False, word=False) %}{% if alone %}{{ _svg(name) }}{% if word %}{{ label }}{% endif %}{% else %}{{ _svg(name) }} {{ label }}{% endif %}{% endmacro %}
{# The attributes of a control that asks before it goes on: the question,
the word of its button, red for what cannot be undone. #}
{% macro _asks(confirm, label, danger) %}{% if confirm %} data-confirm="{{ confirm }}" data-confirm-label="{{ label }}"{% if danger %} data-confirm-danger{% endif %}{% endif %}{% endmacro %}
{# A link that looks like a button, with an icon. ``alone``: the icon
only, ``label`` its tooltip and ``name`` what a screen reader hears. #}
{% macro link_button(url, label, icon, alone=False, word=False, cls="small", name=None) %}{{ _face(icon, label, alone, word) }}{% endmacro %}
{# A button that copies the text of the element ``target`` (an id),
e.g. a secret shown once. Needs app.js: without it, the text is
selectable in one piece. #}
{% macro copy_button(target, label="Copy") %}{% endmacro %}
{# A time in a list: under a day ago as "3 minutes ago", older as date
and time. The full stamp is always the tooltip. #}
{% macro ago(value) %}{% if value %}{% else %}—{% endif %}{% endmacro %}
{# The line under a detail page's heading: where the page sits.
``trail``: (label, url) pairs, the last one the page itself. #}
{% macro breadcrumb(trail) %}
{% endmacro %}
{# A card with a heading. ``meta``: the small line beside it, ``tags``:
markup at the right, ``tight``: the body without padding, for a table. #}
{% macro card(title=None, meta=None, tags=None, tight=False, id=None) %}
{% if title %}
{{ title }}
{% if meta is not none %}{{ meta }}{% endif %}{% if tags %}{{ tags }}{% endif %}{% endif %}
{{ caller() }}
{% endmacro %}
{# Whether a webhook's last post went through. ``detail``: the error
under the tag. #}
{% macro webhook_state(error, detail=True) %}{% if error %}failing{% if detail %}{{ error }}{% endif %}{% else %}ok{% endif %}{% endmacro %}
{# Rights as tags: groups first, then single operations. #}
{% macro rights_tags(groups, operations) %}{% for group in groups %}{{ group }} {% endfor %}{% for operation in operations %}{{ operation }} {% endfor %}{% endmacro %}
{# A secret the service shows once, e.g. a new token: ``title``, the
value in one selectable piece, and the caller says what to do with it. #}
{% macro secret_card(title, value, id="secret") %}
{{ title }}
shown this once
{{ caller() }}
{{ value }}{{ copy_button(id) }}
{% endmacro %}
{# The first card of a detail page: what the record is, read-only. The
caller gives ``fact`` lines. #}
{% macro facts(title, tags=None) %}
{% if caller is defined %}{{ caller() }}{% else %}{{ value | or_missing }}{% endif %}
{% endmacro %}
{# A list that belongs to the record of a detail page, e.g. its tokens
(docs/UI.md 4.2). It creates at its head and acts on its rows. ``add``:
the word of the plus in its header, which opens the form ``add_form``
(an id, a ``row_form`` at the head of the table). #}
{% macro related(title, count=None, meta=None, add=None, add_form=None, add_open=False) %}
{{ title }}
{% if count is not none %}{{ count }}{% endif %}{% if meta %}{{ meta }}{% endif %}{% if add %}{{ toggle(add_form, add, "plus-lg", alone=False, open=add_open) }}{% endif %}
{{ caller() }}
{% endmacro %}
{# A button that opens and closes the form ``target`` (an id) at a row or
at the head of a list. ``alone``: the icon by itself, ``label`` its
tooltip and ``name`` what a screen reader hears. #}
{% macro toggle(target, label, icon, alone=True, name=None, open=False) %}{% endmacro %}
{# The form that unfolds under a row of a table, or at the head of the
list: a row of its own across ``columns``. Without app.js it shows at
once. ``open``: unfolded, e.g. when the list is still empty or a form
came back refused. #}
{% macro row_form(id, columns, open=False) %}
{{ caller() }}
{% endmacro %}
{# A form in a dialog of its own, for a step that asks for more than a
yes, e.g. removing a device with the password and a code. The caller
gives the form, with ``dialog_buttons`` at its end. Opened by a
``dialog_button``. Without app.js it shows in the page. #}
{% macro form_dialog(id, title, text) %}
{% endmacro %}
{% macro dialog_buttons(label, icon="trash", danger=True) %}{% endmacro %}
{# The button that opens the ``form_dialog`` ``target``: an icon alone on
a row, or with its word in a batch bar. #}
{% macro dialog_button(target, label, icon="trash", alone=True, name=None, danger=True) %}{% endmacro %}
{# The tick box of a row for a batch: it belongs to the form ``batch`` (an
id) above the table. ``all`` in the head ticks every row. #}
{% macro tick(batch, name, value, label) %}{% endmacro %}
{% macro tick_all(batch, name, label="Tick all") %}{% endmacro %}
{# The hidden field every form that changes something carries. #}
{% macro csrf_field() %}{% endmacro %}
{# A form that is only a button, e.g. "Delete", with a question before it.
``icon``: an icon beside the word, or with ``alone`` in its place, the
word then the tooltip and ``name`` what a screen reader hears, e.g.
"Revoke the token laptop". A ``danger`` button asks with a red one. #}
{% macro action(url, label, confirm=None, cls="small", fields={}, icon=None, alone=False, word=False, name=None) %}
{% endmacro %}
{# A labelled input. #}
{% macro field(name, label, value="", type="text", hint=None, required=False, cls="", attrs="") %}
{% if hint %}{{ hint }}{% endif %}
{% endmacro %}
{# The filter bar above a list (filters.py): the search first, more
filters folded, the active ones as chips under it. A GET form, so a
filtered list has its URL. ``focus``: the cursor starts in the search,
for a page that is a search. #}
{% macro filter_bar(bar, problem=None, focus=False) %}
{% if problem %}
{{ problem }}
{% endif %}
{% endmacro %}
{# The links below a list: to the next page, and from a later page back to
the first. ``pages``: (more, first), as ``page_links`` gives them.
``back`` and ``on`` name the links: by default for a list newest
first. #}
{% macro pager(pages, back="Newest", on="Older") %}
{% set more, first = pages %}
{% if more or first %}
{% endif %}
{% endmacro %}
{# The options of a folder select: the tree indented by depth, without the
folders in ``exclude``. #}
{% macro folder_options(tree, exclude, selected=None) %}
{% for folder, depth in tree %}{% if folder.id not in exclude %}{% endif %}{% endfor %}
{% endmacro %}
{# The tag beside an account whose user may read mail there and send it
to any address: what an injected instruction needs to carry data out. #}
{% macro anywhere_tag() %}reads and sends anywhere{% endmacro %}
{# The stored credentials of an account, one per line. #}
{% macro credentials(stored) %}{% for credential in stored %}{{ credential.field }}, changed {{ credential.updated_at | when }}{% if not loop.last %} {% endif %}{% else %}—{% endfor %}{% endmacro %}
{# The last card of a detail page, always: its one red button removes the
record, after a question. ``text`` says what happens and what stays. #}
{% macro danger_card(title, text, url, label, confirm) %}
{{ title }}
{{ text }}
{{ action(url, label, confirm=confirm, cls="danger", icon="trash") }}
{% endmacro %}
{# The tabs of a detail page, each a URL of its own (``?tab=``), drawn by
the service: no script. ``items``: (key, label) pairs, ``active`` the
key shown, ``base`` the page. #}
{% macro tabs(items, active, base) %}
{% endmacro %}