{% extends "base.html" %} {% from "_parts.html" import defs, lesson, prose %} {% from "ui/layout.html" import grid, page_header, stack %} {# The landing page: what fjkit is, who it is for, and where to go next. Nothing is explained here for the only time. Every claim on this page is demonstrated on one of the other two โ€” the wiring on Learn, the signatures on Components โ€” so this page stays short and hands over. House style, and the reason this page reads the way it does: one idea per sentence, the takeaway first, and no aside a full stop could have replaced. A reader who stops after the feature list still knows what this is. #} {% set sections = [ {"id": "who", "num": "01", "title": "Who it is for"}, {"id": "box", "num": "02", "title": "What ships in the wheel"}, {"id": "next", "num": "03", "title": "Where to go next"}, ] %} {# Three, and they are the three that decide whether someone keeps reading. Every other promise this project makes is on Learn, where it is demonstrated rather than asserted, and in CHARTER.md ยง2, where the reasoning is. Plain strings, not Markup: a feature that needs a in it has not been written plainly enough for a landing page. #} {% set features = [ ("No build step", "No package.json, no node_modules, no watcher. The stylesheet is compiled when fjkit is released, not when your app runs."), ("One colour knob", "Every colour is a token. Rebranding is one file, and green still means done afterwards."), ("Mounts on your existing API", "Every htmx endpoint answers curl with JSON. Same route, same handler, same return annotation."), ] %} {% block content %} {% call stack(8) %} {% set intro %} An integration of Jinja, Tailwind CSS and shadcn-style components, for FastAPI. {% endset %} {{ page_header("A Fast UI for FastAPI", intro) }} {{ defs("The key features are:", features) }} {# ============================================================== 01 #} {% set i01 %}A back-end developer who needs a real interface and no front-end toolchain.{% endset %} {% call lesson("who", "01", "Who it is for", i01) %} {% call prose() %}

You already write FastAPI. You need navigation, dark mode, a filterable table and a form that validates. This is for you.

If you are bringing React, Vue or Svelte, this is the wrong layer. That is a decision, not a gap.

{% endcall %} {{ defs("What it should cost you", [ ("a first page", "navigation and dark mode in about twenty lines of Python, with no build step"), ("an admin screen", "list, filters, a create form and htmx updates in an afternoon. No CSS, no JavaScript."), ("a rebrand", "one stylesheet of token overrides, loaded after the kit's"), ("an upgrade", "a version bump. The stylesheet lives in the wheel, not in your repository."), ]) }} {% endcall %} {# ============================================================== 02 #} {% set i02 %}One wheel, two runtime dependencies, and nothing for you to compile.{% endset %} {% call lesson("box", "02", "What ships in the wheel", i02) %} {% call grid(cols=2, gap=4) %} {{ defs("Shipped in the package", [ ("templates/ui/", "the macros: layout, buttons, data, forms, tables, tabs, navigation, sidebar, feedback, icons, and the document shell"), ("static/dist/fjkit-.css", "the compiled stylesheet, one per style pack. 234 KB raw, 23.9 KB gzip, under a 28 KB budget the build enforces. A page loads one."), ("static/vendor/", "htmx and Basecoat's JavaScript, pinned and served out of the package"), ("1,767 icons", "Lucide, inlined by name. No icon font, no sprite request, no runtime JS."), ]) }} {{ defs("The whole surface you touch", [ ("FjkitConfig, mount_fjkit", "the wiring, once per app"), ("@render", "name a template on the decorator; the handler returns data"), ("fjkit check", "the vocabulary gate. Run it in your CI."), ("fjkit eject", "the escape hatch: take one macro into your app and edit it"), ]) }} {% endcall %} {% call prose() %}

Requirements: Python 3.13 or newer, and two runtime dependencies โ€” FastAPI and Jinja2. Adding a third needs an argument nobody has made yet.

{% endcall %} {% endcall %} {# ============================================================== 03 #} {% set i03 %}Two pages. One shows you the wiring, the other shows you every macro.{% endset %} {% call lesson("next", "03", "Where to go next", i03) %} {% set n_learn %}how the kit is wired, what htmx sends, and the gate that fails a build{% endset %} {% set n_components %}every macro, live, with the call that made it{% endset %} {{ defs("On this site", [ ("Learn", n_learn), ("Components", n_components), ]) }} {% endcall %} {% endcall %} {% endblock %}