{% 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 %} {# 英文版 `templates/cheatsheet.html` 的翻譯。結構逐段對應,只有散文不同。 清單內容全部來自 `cheatsheet.py`,傳進來時已經是這個語言,所以這一頁不挑字串。 模板一旦自己組字串,兩個語言的索引就可能列出不同的 macro。 #} {% set sections = [{"id": "reading", "title": "怎麼讀這張表"}] + sheet.rail + [{"id": "shell", "title": "外殼"}, {"id": "globals", "title": "Globals"}, {"id": "htmx", "title": "htmx 屬性"}, {"id": "missing", "title": "這裡找不到的時候"}] %} {% 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 %} {% 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 %} kit 出貨的每一支 macro,依用途分組,並在每一列標出這支 macro 要不要用區塊呼叫、區塊裡放什麼。 元件那一頁看它們跑起來,這一頁用來查。 {% endset %} {{ page_header(page.title, intro) }} {# ============================================================== reading #} {% set lead_reading %}一列上有什麼,以及兩條每一列都適用的規則。{% endset %} {% call band("reading", "怎麼讀這張表", lead_reading) %} {% call prose() %}

Jinja macro 有兩種呼叫方式,從名字看不出來是哪一種。裡面不放東西的 macro 直接印出來。會包住東西的 macro 用 {% raw %}{% call %}{% endraw %} 呼叫,{% raw %}{% call %}{% endraw %} 與 {% raw %}{% endcall %}{% endraw %} 之間的內容交給 macro 擺放,Jinja 稱之為 caller 區塊。底下每一支需要區塊的 macro 都掛了一個標籤。

{% endcall %} {{ code_block(sheet.samples.shapes, label="兩種形狀", data_lang="jinja") }} {% call grid(cols=2, gap=4) %} {% set c_macro %}那一行呼叫,含每個參數與預設值。清單上方的標題就是要 import 的檔案{% endset %} {% set c_block %}在列的右邊,只出現在有區塊的列:這支 macro 要用 {% raw %}{% call %}{% endraw %} 呼叫,標籤寫的是區塊裡放什麼。沒有標籤就用 {% raw %}{{ }}{% endraw %} 印出來{% endset %} {% set c_note %}簽名沒說的事;簽名說完的就不寫{% endset %} {{ defs("一列上有什麼", [ ("簽名", c_macro), ("區塊標籤", c_block), ("底下那一行說明", c_note), ]) }} {% set r_attrs %}簽名裡沒有的關鍵字一律變成屬性,底線換成連字號:hx_post="/tasks" 到了標記裡是 hx-post="/tasks"。每一支 macro 的每一個 hx-*、aria-*、data-* 都走這條路徑{% endset %} {% set r_variant %}variant、tone、category 指的是角色(success、destructive、muted),不是顏色。顏色歸 token 層,換品牌只動一個地方{% endset %} {{ defs("兩條通則", [ ("多出來的關鍵字", r_attrs), ("用角色,不用顏色", 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 %}是 block,不是 macro:唯一一個用 extends 而不是 import 的檔案。{% endset %} {% call band("shell", "外殼", lead_shell) %} {% call prose() %}

ui/shell.html 提供 <head>、主題閃爍防護、資源連結, 以及 header/main/footer 骨架。app 在自己的 base.html 裡 extends 它一次, 再填需要的 block。sidebar 與 nav 只填一個:外殼依照填了哪一個 排出不同的標頭,兩個都填會得到兩套導覽。

{% 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 %}每個模板裡都有,不用 import,也不用從 context 傳。{% endset %} {% call band("globals", "Globals", lead_globals) %} {{ name_list("build_environment()", sheet.globals) }} {% endcall %} {# ============================================================== htmx #} {% set lead_htmx %}它們不屬於 fjkit,但會傳給 fjkit macro,所以列在索引旁邊。{% endset %} {% call band("htmx", "htmx 屬性", lead_htmx) %} {% call prose() %}

這裡每一個都以多出來的關鍵字傳給 macro,再進到標記裡:{% raw %}{{ button("Refresh", hx_get="/tasks/board", hx_target="#board") }}{% endraw %}。底線在途中變成連字號,整套整合只有這件事:kit 裡沒有一支 macro 有 htmx 專屬參數,也不需要有。完整參考是 htmx.org/reference,底下列的是 fjkit 頁面實際用到的部分。

{% 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 %}答案是某個參數、某個關鍵字,或一張 issue,依這個順序找。{% endset %} {% call band("missing", "這裡找不到的時候", lead_missing) %} {% call grid(cols=2, gap=4) %} {{ defs("找不到想要的 macro 時", [ ("先看參數", "多數需求對應到一個已經存在的關鍵字:size、tone、padded、align"), ("直接傳過去", "多出來的關鍵字一律變成屬性,涵蓋所有 hx-*、aria-* 與 data-*"), ("fjkit eject badge", "把那一支 macro 拿進你的 app 改;同檔的其他 macro 由 kit 再匯出,照樣收上游的修正"), ("開一張 issue", "被擋下來的 class 指名了還不存在的元件,那就是最好的回報內容"), ]) }} {% set d_learn %}各個零件怎麼接,以及 htmx 送出什麼{% endset %} {% set d_components %}每一支 macro 的實際渲染,參數可以現場調整{% endset %} {{ defs("接著讀", [ ("上手", d_learn), ("元件", d_components), ("examples/fjkit-demo/", "同一批 macro 放在一支能跑的 app 裡,在 repo 中"), ("src/fjkit/static/src/fjkit.css", "每個 variant 背後那張 token 表"), ]) }} {% endcall %} {% endcall %} {% endcall %} {% endblock %}