Skip to content

Layouts

Tools for building layouts and several simple layouts for quick prototyping.

filter_body_tags

filter_body_tags(tags)

Given a list of tags, only list the ones that belong in body of an HTML document.

Source code in src/air/layouts.py
23
24
25
def filter_body_tags(tags) -> list:
    """Given a list of tags, only list the ones that belong in body of an HTML document."""
    return [t for t in tags if not isinstance(t, HEAD_TAG_TYPES)]

filter_head_tags

filter_head_tags(tags)

Given a list of tags, only list the ones that belong in head of an HTML document.

Source code in src/air/layouts.py
28
29
30
def filter_head_tags(tags) -> list:
    """Given a list of tags, only list the ones that belong in head of an HTML document."""
    return [t for t in tags if isinstance(t, HEAD_TAG_TYPES)]

mvpcss

mvpcss(*children, is_htmx=False, **kwargs)

Renders the basic layout with MVP.css and HTMX for quick prototyping

  1. At the top level HTML head tags are put in the <head> tag
  2. Otherwise everything is put in the <body>
  3. Header and Nav tags are placed in the top of the body above the Main tag
  4. If is_htmx is True, then the layout isn't included. This is to support the hx_boost feature of HTMX

The mvpcss function is a quick prototyping tool. It isn't designed to be extensible. Rather the mvpcss layout function makes it easy to roll out quick demonstrations and proofs-of-concept. For more advanced layouts like Eidos or a full-fledged MVP.css implementation, you'll have to create your own layouts.

Parameters:

Name Type Description Default
children

These typically inherit from air.Tag but can be anything

()
is_htmx bool

Whether or not HTMX sent the request from the page

False

Example:

from fastapi import Depends
import air

app = air.Air()


@app.page
async def index(is_htmx: bool = Depends(air.is_htmx_request)):
    return air.layouts.mvpcss(
        air.Title("Home"),
        air.Article(
            air.H1("Welcome to Air"), air.P(air.A("Click to go to Dashboard", href="/dashboard")), hx_boost="true"
        ),
        is_htmx=is_htmx
    )


@app.page
async def dashboard(is_htmx: bool = Depends(air.is_htmx_request)):
    return air.layouts.mvpcss(
        air.Title("Dashboard"), air.Article(air.H1("Dashboard"), air.P(air.A("Go home", href="/")), hx_boost="true"),
        is_htmx=is_htmx
    )
Source code in src/air/layouts.py
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
def mvpcss(*children, is_htmx: bool = False, **kwargs):
    """Renders the basic layout with MVP.css and HTMX for quick prototyping

    1. At the top level HTML head tags are put in the `<head>` tag
    2. Otherwise everything is put in the `<body>`
    3. `Header` and `Nav` tags are placed in the top of the body above the `Main` tag
    4. If `is_htmx` is True, then the layout isn't included. This is to support the `hx_boost`
        feature of HTMX

    The `mvpcss` function is a quick prototyping tool. It isn't designed to be extensible.
        Rather the `mvpcss` layout function makes it easy to roll out quick demonstrations and proofs-of-concept.
        For more advanced layouts like Eidos or a full-fledged MVP.css implementation,
        you'll have to create your own layouts.

    Args:
        children: These typically inherit from air.Tag but can be anything
        is_htmx: Whether or not HTMX sent the request from the page

    Example:

        from fastapi import Depends
        import air

        app = air.Air()


        @app.page
        async def index(is_htmx: bool = Depends(air.is_htmx_request)):
            return air.layouts.mvpcss(
                air.Title("Home"),
                air.Article(
                    air.H1("Welcome to Air"), air.P(air.A("Click to go to Dashboard", href="/dashboard")), hx_boost="true"
                ),
                is_htmx=is_htmx
            )


        @app.page
        async def dashboard(is_htmx: bool = Depends(air.is_htmx_request)):
            return air.layouts.mvpcss(
                air.Title("Dashboard"), air.Article(air.H1("Dashboard"), air.P(air.A("Go home", href="/")), hx_boost="true"),
                is_htmx=is_htmx
            )

    """
    body_tags = filter_body_tags(children)
    head_tags = filter_head_tags(children)

    if is_htmx:
        return Children(Main(*body_tags), *head_tags).render()

    return Html(
        Head(
            Link(rel="stylesheet", href="https://unpkg.com/mvp.css"),
            Style("footer, header, main { padding: 1rem; } nav {margin-bottom: 1rem;}"),
            Script(
                src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.6/dist/htmx.min.js",
                integrity="sha384-Akqfrbj/HpNVo8k11SXBb6TlBWmXXlYQrCSqEWmyKJe+hDm3Z/B2WVG4smwBkRVm",
                crossorigin="anonymous",
            ),
            *head_tags,
        ),
        Body(
            _header(body_tags),
            Main(*[x for x in body_tags if not isinstance(x, Header)]),
        ),
    ).render()

picocss

picocss(*children, is_htmx=False, **kwargs)

Renders the basic layout with PicoCSS and HTMX for quick prototyping

  1. At the top level HTML head tags are put in the <head> tag
  2. Otherwise everything is put in the <body>
  3. If is_htmx is True, then the layout isn't included. This is to support the hx_boost feature of HTMX
PicoCSS is a quick prototyping tool. It isn't designed to be extensible.

Rather the pico layout function makes it easy to roll out quick demonstrations and proofs-of-concept. For more advanced layouts like Eidos or a full-fledged PicoCSS implementation, you'll have to create your own layouts.

Parameters:

Name Type Description Default
children

These typically inherit from air.Tag but can be anything

()
is_htmx bool

Whether or not HTMX sent the request from the page

False
Source code in src/air/layouts.py
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
def picocss(*children, is_htmx: bool = False, **kwargs):
    """Renders the basic layout with PicoCSS and HTMX for quick prototyping

    1. At the top level HTML head tags are put in the `<head>` tag
    2. Otherwise everything is put in the `<body>`
    3. If `is_htmx` is True, then the layout isn't included. This is to support the `hx_boost`
        feature of HTMX

    Note: `PicoCSS` is a quick prototyping tool. It isn't designed to be extensible.
        Rather the `pico` layout function makes it easy to roll out quick demonstrations and proofs-of-concept.
        For more advanced layouts like Eidos or a full-fledged PicoCSS implementation,
        you'll have to create your own layouts.

    Args:
        children: These typically inherit from air.Tag but can be anything
        is_htmx: Whether or not HTMX sent the request from the page

    """
    body_tags = filter_body_tags(children)
    head_tags = filter_head_tags(children)

    if is_htmx:
        return Children(Main(*body_tags, class_="container"), *head_tags).render()

    return Html(
        Head(
            Link(
                rel="stylesheet",
                href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css",
            ),
            Script(
                src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.6/dist/htmx.min.js",
                integrity="sha384-Akqfrbj/HpNVo8k11SXBb6TlBWmXXlYQrCSqEWmyKJe+hDm3Z/B2WVG4smwBkRVm",
                crossorigin="anonymous",
            ),
            *head_tags,
        ),
        Body(Main(*body_tags, class_="container")),
    ).render()