{% extends "base.html" %} {% from "_parts.html" import band, defs, prose %} {% from "ui/data.html" import badge, card, code_block, item, item_list %} {% from "ui/layout.html" import grid, page_header, stack %} {# The index: every macro in `src/fjkit/templates/ui/`, one row each. It used to be section 14 of the Components page — one pre-formatted string, ninety macros aligned with spaces, annotated with a `·` no legend explained. Two problems, and splitting the page fixes only the first: it sat at the tail of a page nobody scrolls to the end of, and the fact a reader most often wants from an index — does this take a `{% raw %}{% call %}{% endraw %}` block, and what goes inside it — was encoded rather than stated. So the annotation became a badge on the row, in words. The rows come from `cheatsheet.py` already in this language, which is why nothing below chooses a string: a page that assembled the phrases would be the one place the English and Chinese indexes could describe different macros. Components stays the page you read; this is the page you look things up in. #} {% set sections = [{"id": "reading", "title": "How to read this"}] + sheet.rail + [{"id": "shell", "title": "The shell"}, {"id": "globals", "title": "Globals"}, {"id": "htmx", "title": "htmx attributes"}, {"id": "missing", "title": "When it is not here"}] %} {# One row, three parts: the signature, the note under it, and — only when the macro is called with one — the badge naming its block. `item_list` rather than `table`, because Basecoat's `.table td` is `white-space: nowrap`, which is right for a data table and wrong for a column of sentences. `item` is the kit's answer for definitions, as its signature comment says, and `clamp=false` grew for exactly this: a description that runs past two lines. Absence carries meaning here. A row with no badge takes no block, which is most of them, and a column of em dashes would be noise on every screen. #} {% macro macro_list(file) %} {% call card(file.name, padded=false) %} {% call item_list() %} {% for macro in file.macros %} {% set signature %}{{ macro.call }}{% endset %} {% set block %}{% if macro.block %}{{ badge(macro.block, variant="outline") }}{% endif %}{% endset %} {{ item(signature, macro.note, actions=block, clamp=false) }} {% endfor %} {% endcall %} {% endcall %} {% endmacro %} {# The same row without the badge: a name, and one line on what it is for. #} {% macro name_list(heading, entries, description=none) %} {% call card(heading, description, padded=false) %} {% call item_list() %} {% for entry in entries %} {% set name %}{{ entry.name }}{% endset %} {{ item(name, entry.note, clamp=false) }} {% endfor %} {% endcall %} {% endcall %} {% endmacro %} {% block content %} {% call stack(8) %} {% set intro %} Every macro the kit ships, grouped by what it is for, with the one question an index is asked most often answered on the row itself: does this take a block, and what goes inside it. The Components page is where you see them running; this is where you look one up. {% endset %} {{ page_header(page.title, intro) }} {# ============================================================== reading #} {% set lead_reading %}What is on a row, and two rules that apply to every one of them.{% endset %} {% call band("reading", "How to read this", lead_reading) %} {% call prose() %}

A Jinja macro is called in one of two ways, and the name does not tell you which. A macro with nothing inside it is printed. A macro that wraps something is called with {% raw %}{% call %}{% endraw %}, and whatever sits between that and {% raw %}{% endcall %}{% endraw %} is handed to the macro to place. Jinja calls that the caller block, and every macro below that wants one carries a badge saying what goes in it.

{% endcall %} {{ code_block(sheet.samples.shapes, label="the two shapes", data_lang="jinja") }} {% call grid(cols=2, gap=4) %} {% set c_macro %}the call, with every parameter and its default. The heading above each list is the file you import it from{% endset %} {% set c_block %}on the right of a row, and only on the rows that have one: this macro is called with {% raw %}{% call %}{% endraw %}, and the badge says what goes inside. No badge means print it with {% raw %}{{ }}{% endraw %}{% endset %} {% set c_note %}what the signature does not say. Absent when the signature says all of it{% endset %} {{ defs("What is on a row", [ ("The signature", c_macro), ("A block badge", c_block), ("One line under it", c_note), ]) }} {% set r_attrs %}anything you pass that is not in the signature becomes an attribute, with underscores turned into dashes: hx_post="/tasks" arrives as hx-post="/tasks". That is every hx-*, aria-* and data-*, on every macro{% endset %} {% set r_variant %}variant, tone and category name a role — success, destructive, muted — never a colour. The colour is the token layer's, so a rebrand moves it once{% endset %} {{ defs("Two rules, everywhere", [ ("Extra keywords", r_attrs), ("Roles, not colours", r_variant), ]) }} {% endcall %} {% endcall %} {# ============================================================== the macros #} {% for group in sheet.groups %} {% call band(group.id, group.title, group.lead) %} {% for file in group.files %}{{ macro_list(file) }}{% endfor %} {% endcall %} {% endfor %} {# ============================================================== shell #} {% set lead_shell %}Blocks, not macros — the one file you extend rather than import.{% endset %} {% call band("shell", "The shell", lead_shell) %} {% call prose() %}

ui/shell.html carries the <head>, the theme flash-guard, the asset links and the header/main/footer skeleton. An app extends it once, in its own base.html, and fills the blocks it needs. Fill sidebar or nav, never both: the shell lays the header out differently for each, and filling both gives you two navigations.

{% endcall %} {{ code_block(sheet.samples.shell, label="app/templates/base.html", data_lang="jinja") }} {{ name_list("ui/shell.html", sheet.shell_blocks) }} {% endcall %} {# ============================================================== globals #} {% set lead_globals %}In every template already — no import, no context variable.{% endset %} {% call band("globals", "Globals", lead_globals) %} {{ name_list("build_environment()", sheet.globals) }} {% endcall %} {# ============================================================== htmx #} {% set lead_htmx %}Not fjkit's, but passed to fjkit macros — so they belong next to the index.{% endset %} {% call band("htmx", "htmx attributes", lead_htmx) %} {% call prose() %}

Every one of these reaches the markup as an extra keyword on a macro: {% raw %}{{ button("Refresh", hx_get="/tasks/board", hx_target="#board") }}{% endraw %}. Underscores become dashes on the way through, and that is the whole integration: no macro has an htmx-specific parameter, and none needs one. The full reference is htmx.org/reference; what follows is what a fjkit page uses.

{% endcall %} {% for part in sheet.htmx %} {% call card(part.title, part.lead, padded=false) %} {% call item_list() %} {% for entry in part.rows %} {% set written %}{{ entry.call }}{% endset %} {{ item(written, entry.note, clamp=false) }} {% endfor %} {% endcall %} {% endcall %} {% endfor %} {% endcall %} {# ============================================================== missing #} {% set lead_missing %}The answer is a parameter, a keyword, or an issue — in that order.{% endset %} {% call band("missing", "When it is not here", lead_missing) %} {% call grid(cols=2, gap=4) %} {{ defs("When a macro is missing", [ ("check the parameters", "most requests are a keyword that already exists — size, tone, padded, align"), ("pass it through", "any extra keyword becomes an attribute, which covers every hx-*, aria-* and data-*"), ("fjkit eject badge", "take that one macro into your app to edit; every other macro in its file is re-exported from the kit and keeps its fixes"), ("open an issue", "a blocked class names the component that does not exist yet; that is the report"), ]) }} {% set d_learn %}how the pieces fit, and what htmx sends{% endset %} {% set d_components %}every macro running, with the knobs turned{% endset %} {{ defs("Read next", [ ("Learn", d_learn), ("Components", d_components), ("examples/fjkit-demo/", "these macros inside a working app, in the repo"), ("src/fjkit/static/src/fjkit.css", "the token table behind every variant"), ]) }} {% endcall %} {% endcall %} {% endcall %} {% endblock %}