FastUI icon indicating copy to clipboard operation
FastUI copied to clipboard

Custom Head Component

Open 0417taehyun opened this issue 1 year ago • 4 comments

Make custom head tag with meta, title, script, and link tags.

For example, it looks like the one below.

class Head(pydanctic.BaseModel,  extra='forbid')
    elements: list[AnyHeadElement]


def render_head_element(head: Head) -> str:
    additional_tags: str = "\n".join([element in element in head.elements])
    return f"""
    <head>
      <meta charset="UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      {additional_tags}
      <script type="module" crossorigin src="{_PREBUILT_CDN_URL}/index.js"></script>
      <link rel="stylesheet" crossorigin href="{_PREBUILT_CDN_URL}/index.css">        
    </head>
"""


def prebuilt_html(head: Head):
    """
    Returns a simple HTML page which includes the FastUI react frontend, loaded from https://www.jsdelivr.com/.

    Arguments:
        title: page title

    Returns:
        HTML string which can be returned by an endpoint to serve the FastUI frontend.
    """
    # language=HTML
    head: str = render_head_element(head=head)
    return f"""\
<!doctype html>
<html lang="en">
  {head}
  <body>
    <div id="root"></div>
  </body>
</html>
"""

If it is reasonable, can I contribute as pull request?

0417taehyun avatar Dec 02 '23 19:12 0417taehyun

Seems reasonable, yes pr please.

Also they might want to customise the CDN URL they use.

samuelcolvin avatar Dec 05 '23 06:12 samuelcolvin

One suggestion from me might be Knio/dominate for more pythonic way to build the HTML instead of writing plain HTML.

@samuelcolvin I can work on it if you are OK to add dominate as a dependency or I can come up with a simpler/smaller alternative to dominate.

hasansezertasan avatar Dec 07 '23 00:12 hasansezertasan

Looks like a cool library, but I'd rather not add the dependency for just this.

samuelcolvin avatar Dec 07 '23 05:12 samuelcolvin

Thank you @samuelcolvin for your response.

@0417taehyun, I believe this could be a code-first solution for you.

import dominate
from dominate.tags import div, link, meta, script
from fastapi import FastAPI
from fastapi.responses import HTMLResponse

app = FastAPI()

@app.get(
    path="/{path:path}",
    response_class=HTMLResponse,
)
async def html_landing() -> HTMLResponse:
    """Simple HTML page which serves the React app, comes last as it matches all paths."""
    doc = dominate.document(title="FastUI Demo", lang="en")

    with doc.head:
        meta(charset="utf-8")
        meta(
            name="viewport",
            content="width=device-width, initial-scale=1.0",
        )
        script(
            type="module",
            src="https://cdn.jsdelivr.net/npm/@pydantic/[email protected]/dist/assets/index.js",
        )
        link(
            rel="stylesheet",
            href="https://cdn.jsdelivr.net/npm/@pydantic/[email protected]/dist/assets/index.css",
        )

    with doc:
        div(id="root")

    return doc.render()

HTML is created (and editable) programmatically without any JSX or template mess. You can update the title of the document or add another element into the head tag with ease.

hasansezertasan avatar Dec 07 '23 09:12 hasansezertasan