diff --git "a/llms-ctx-MonsterUI.txt" "b/llms-ctx-MonsterUI.txt" new file mode 100644--- /dev/null +++ "b/llms-ctx-MonsterUI.txt" @@ -0,0 +1,7292 @@ +> MonsterUI is a python library which brings styling to python for FastHTML apps.# monsterui Module Documentation + +## monsterui.core + +- `class ThemeRadii(Enum)` + Members: none, sm, md, lg + + +- `class ThemeShadows` + +- `class ThemeFont` + +- `class Theme(Enum)` + Selector to choose theme and get all headers needed for app. Includes frankenui + tailwind + daisyui + highlight.js options + Members: slate, stone, gray, neutral, red, rose, orange, green, blue, yellow, violet, zinc + + - `headers(self, mode, daisy, highlightjs, katex, radii, shadows, font)` + Create frankenui and tailwind cdns + + - `local_headers(self, mode, static_dir, daisy, highlightjs, katex, radii, shadows, font)` + Create headers using local files downloaded from CDNs + + +## monsterui.daisy + +- `class AlertT(Enum)` + Alert styles from DaisyUI + Members: info, success, warning, error + + +- `def Alert(*c, **kwargs)` + Alert informs users about important events. + +- `class StepsT(Enum)` + Options for Steps + Members: vertical, horizonal + + +- `class StepT(Enum)` + Step styles for LiStep + Members: primary, secondary, accent, info, success, warning, error, neutral + + +- `def Steps(*li, **kwargs)` + Creates a steps container + +- `def LiStep(*c, **kwargs)` + Creates a step list item + +- `class LoadingT(Enum)` + Members: spinner, dots, ring, ball, bars, infinity, xs, sm, md, lg + + +- `def Loading(cls, htmx_indicator, **kwargs)` + Creates a loading animation component + +- `class ToastHT(Enum)` + Horizontal position for Toast + Members: start, center, end + + +- `class ToastVT(Enum)` + Vertical position for Toast + Members: top, middle, bottom + + +## monsterui.foundations + +> Data Structures and Utilties + +- `def stringify(o)` + Converts input types into strings that can be passed to FT components + +- `class VEnum(Enum)` + Members: + + - `__str__(self)` + - `__add__(self, other)` + - `__radd__(self, other)` + +## monsterui.franken + +- `class TextT(Enum)` + Text Styles from https://franken-ui.dev/docs/text + Members: paragraph, lead, meta, gray, italic, xs, sm, lg, xl, light, normal, medium, bold, extrabold, muted, primary, secondary, success, warning, error, info, left, right, center, justify, start, end, top, middle, bottom, truncate, break_, nowrap, underline, highlight + + +- `class TextPresets(Enum)` + Common Typography Presets + Members: muted_sm, muted_lg, bold_sm, bold_lg, md_weight_sm, md_weight_muted + + +- `def CodeSpan(*c, **kwargs)` + A CodeSpan with Styling + +- `def CodeBlock(*c, **kwargs)` + CodeBlock with Styling + +- `def H1(*c, **kwargs)` + H1 with styling and appropriate size + +- `def H2(*c, **kwargs)` + H2 with styling and appropriate size + +- `def H3(*c, **kwargs)` + H3 with styling and appropriate size + +- `def H4(*c, **kwargs)` + H4 with styling and appropriate size + +- `def H5(*c, **kwargs)` + H5 with styling and appropriate size + +- `def H6(*c, **kwargs)` + H6 with styling and appropriate size + +- `def Subtitle(*c, **kwargs)` + Styled muted_sm text designed to go under Headings and Titles + +- `def Q(*c, **kwargs)` + Styled quotation mark + +- `def Em(*c, **kwargs)` + Styled emphasis text + +- `def Strong(*c, **kwargs)` + Styled strong text + +- `def I(*c, **kwargs)` + Styled italic text + +- `def Small(*c, **kwargs)` + Styled small text + +- `def Mark(*c, **kwargs)` + Styled highlighted text + +- `def Del(*c, **kwargs)` + Styled deleted text + +- `def Ins(*c, **kwargs)` + Styled inserted text + +- `def Sub(*c, **kwargs)` + Styled subscript text + +- `def Sup(*c, **kwargs)` + Styled superscript text + +- `def Blockquote(*c, **kwargs)` + Blockquote with Styling + +- `def Caption(*c, **kwargs)` + Styled caption text + +- `def Cite(*c, **kwargs)` + Styled citation text + +- `def Time(*c, **kwargs)` + Styled time element + +- `def Address(*c, **kwargs)` + Styled address element + +- `def Abbr(*c, **kwargs)` + Styled abbreviation with dotted underline + +- `def Dfn(*c, **kwargs)` + Styled definition term with italic and medium weight + +- `def Kbd(*c, **kwargs)` + Styled keyboard input with subtle background + +- `def Samp(*c, **kwargs)` + Styled sample output with subtle background + +- `def Var(*c, **kwargs)` + Styled variable with italic monospace + +- `def Figure(*c, **kwargs)` + Styled figure container with card-like appearance + +- `def Details(*c, **kwargs)` + Styled details element + +- `def Summary(*c, **kwargs)` + Styled summary element + +- `def Data(*c, **kwargs)` + Styled data element + +- `def Meter(*c, **kwargs)` + Styled meter element + +- `def S(*c, **kwargs)` + Styled strikethrough text (different semantic meaning from Del) + +- `def U(*c, **kwargs)` + Styled underline (for proper names in Chinese, proper spelling etc) + +- `def Output(*c, **kwargs)` + Styled output element for form results + +- `def PicSumImg(h, w, id, grayscale, blur, **kwargs)` + Creates a placeholder image using https://picsum.photos/ + +- `class ButtonT(Enum)` + Options for styling Buttons + Members: default, ghost, primary, secondary, destructive, text, link, xs, sm, lg, xl, icon + + +- `def Button(*c, **kwargs)` + Button with Styling (defaults to `submit` for form submission) + +- `class ContainerT(Enum)` + Max width container sizes from https://franken-ui.dev/docs/container + Members: xs, sm, lg, xl, expand + + +- `class BackgroundT(Enum)` + Members: muted, primary, secondary, default + + +- `def Container(*c, **kwargs)` + Div to be used as a container that often wraps large sections or a page of content + +- `def Titled(title, *c, **kwargs)` + Creates a standard page structure for titled page. Main(Container(title, content)) + +- `class DividerT(Enum)` + Divider Styles from https://franken-ui.dev/docs/divider + Members: icon, sm, vertical + + +- `def Divider(*c, **kwargs)` + Divider with default styling and margin + +- `def DividerSplit(*c)` + Creates a simple horizontal line divider with configurable thickness and vertical spacing + +- `def Article(*c, **kwargs)` + A styled article container for blog posts or similar content + +- `def ArticleTitle(*c, **kwargs)` + A title component for use within an Article + +- `def ArticleMeta(*c, **kwargs)` + A metadata component for use within an Article showing things like date, author etc + +- `class SectionT(Enum)` + Section styles from https://franken-ui.dev/docs/section + Members: default, muted, primary, secondary, xs, sm, lg, xl, remove_vertical + + +- `def Section(*c, **kwargs)` + Section with styling and margins + +- `def Form(*c, **kwargs)` + A Form with default spacing between form elements + +- `def Fieldset(*c, **kwargs)` + A Fieldset with default styling + +- `def Legend(*c, **kwargs)` + A Legend with default styling + +- `def Input(*c, **kwargs)` + An Input with default styling + +- `def Radio(*c, **kwargs)` + A Radio with default styling + +- `def CheckboxX(*c, **kwargs)` + A Checkbox with default styling + +- `def Range(*c, **kwargs)` + A Range with default styling + +- `def TextArea(*c, **kwargs)` + A Textarea with default styling + +- `def Switch(*c, **kwargs)` + A Switch with default styling + +- `def Upload(*c, **kwargs)` + A file upload component with default styling + +- `def UploadZone(*c, **kwargs)` + A file drop zone component with default styling + +- `def FormLabel(*c, **kwargs)` + A Label with default styling + +- `class LabelT(Enum)` + Members: primary, secondary, danger + + +- `def Label(*c, **kwargs)` + FrankenUI labels, which look like pills + +- `def UkFormSection(title, description, *c)` + A form section with a title, description and optional button + +- `def GenericLabelInput(label, lbl_cls, input_cls, container, cls, id, input_fn, **kwargs)` + `Div(Label,Input)` component with Uk styling injected appropriately. Generally you should higher level API, such as `LabelInput` which is created for you in this library + +- `def LabelInput(label, lbl_cls, input_cls, cls, id, **kwargs)` + A `FormLabel` and `Input` pair that provides default spacing and links/names them based on id + +- `def LabelRadio(label, lbl_cls, input_cls, container, cls, id, **kwargs)` + A FormLabel and Radio pair that provides default spacing and links/names them based on id + +- `def LabelCheckboxX(label, lbl_cls, input_cls, container, cls, id, **kwargs)` + A FormLabel and CheckboxX pair that provides default spacing and links/names them based on id + +- `def Options(*c)` + Helper function to wrap things into `Option`s for use in `Select` + +- `def Select(*option, **kwargs)` + Creates a select dropdown with uk styling and option for adding a search box + +- `def LabelSelect(*option, **kwargs)` + A FormLabel and Select pair that provides default spacing and links/names them based on id + +- `@delegates(GenericLabelInput, but=['input_fn', 'cls']) def LabelRange(label, lbl_cls, input_cls, cls, id, value, min, max, step, label_range, **kwargs)` + A FormLabel and Range pair that provides default spacing and links/names them based on id + +- `class AT(Enum)` + Link styles from https://franken-ui.dev/docs/link + Members: muted, text, reset, primary, classic + + +- `class ListT(Enum)` + List styles using Tailwind CSS + Members: disc, circle, square, decimal, hyphen, bullet, divider, striped + + +- `def ModalContainer(*c, **kwargs)` + Creates a modal container that components go in + +- `def ModalDialog(*c, **kwargs)` + Creates a modal dialog + +- `def ModalHeader(*c, **kwargs)` + Creates a modal header + +- `def ModalBody(*c, **kwargs)` + Creates a modal body + +- `def ModalFooter(*c, **kwargs)` + Creates a modal footer + +- `def ModalTitle(*c, **kwargs)` + Creates a modal title + +- `def ModalCloseButton(*c, **kwargs)` + Creates a button that closes a modal with js + +- `def Modal(*c, **kwargs)` + Creates a modal with the appropriate classes to put the boilerplate in the appropriate places for you + +- `def Placeholder(*c, **kwargs)` + Creates a placeholder + +- `def Progress(*c, **kwargs)` + Creates a progress bar + +- `def UkIcon(icon, height, width, stroke_width, cls, **kwargs)` + Creates an icon using lucide icons + +- `def UkIconLink(icon, height, width, stroke_width, cls, button, **kwargs)` + Creates an icon link using lucide icons + +- `def DiceBearAvatar(seed_name, h, w)` + Creates an Avatar using https://dicebear.com/ + +- `def Center(*c, **kwargs)` + Centers contents both vertically and horizontally by default + +- `class FlexT(Enum)` + Flexbox modifiers using Tailwind CSS + Members: block, inline, left, center, right, between, around, stretch, top, middle, bottom, row, row_reverse, column, column_reverse, nowrap, wrap, wrap_reverse + + +- `def Grid(*div, **kwargs)` + Creates a responsive grid layout with smart defaults based on content + +- `def DivFullySpaced(*c, **kwargs)` + Creates a flex div with it's components having as much space between them as possible + +- `def DivCentered(*c, **kwargs)` + Creates a flex div with it's components centered in it + +- `def DivLAligned(*c, **kwargs)` + Creates a flex div with it's components aligned to the left + +- `def DivRAligned(*c, **kwargs)` + Creates a flex div with it's components aligned to the right + +- `def DivVStacked(*c, **kwargs)` + Creates a flex div with it's components stacked vertically + +- `def DivHStacked(*c, **kwargs)` + Creates a flex div with it's components stacked horizontally + +- `class NavT(Enum)` + Members: default, primary, secondary + + +- `def NavContainer(*li, **kwargs)` + Creates a navigation container (useful for creating a sidebar navigation). A Nav is a list (NavBar is something different) + +- `def NavParentLi(*nav_container, **kwargs)` + Creates a navigation list item with a parent nav for nesting + +- `def NavDividerLi(*c, **kwargs)` + Creates a navigation list item with a divider + +- `def NavHeaderLi(*c, **kwargs)` + Creates a navigation list item with a header + +- `def NavSubtitle(*c, **kwargs)` + Creates a navigation subtitle + +- `def NavCloseLi(*c, **kwargs)` + Creates a navigation list item with a close button + +- `class ScrollspyT(Enum)` + Members: underline, bold + + +- `def NavBar(*c)` + Creates a responsive navigation bar with mobile menu support + +- `def SliderContainer(*c, **kwargs)` + Creates a slider container + +- `def SliderItems(*c, **kwargs)` + Creates a slider items container + +- `def SliderNav(cls, prev_cls, next_cls, **kwargs)` + Navigation arrows for Slider component + +- `def Slider(*c, **kwargs)` + Creates a slider with optional navigation arrows + +- `def DropDownNavContainer(*li, **kwargs)` + A Nav that is part of a DropDown + +- `def TabContainer(*li, **kwargs)` + A TabContainer where children will be different tabs + +- `class CardT(Enum)` + Card styles from UIkit + Members: default, primary, secondary, destructive, hover + + +- `def CardTitle(*c, **kwargs)` + Creates a card title + +- `def CardHeader(*c, **kwargs)` + Creates a card header + +- `def CardBody(*c, **kwargs)` + Creates a card body + +- `def CardFooter(*c, **kwargs)` + Creates a card footer + +- `def CardContainer(*c, **kwargs)` + Creates a card container + +- `def Card(*c, **kwargs)` + Creates a Card with a header, body, and footer + +- `class TableT(Enum)` + Members: divider, striped, hover, sm, lg, justify, middle, responsive + + +- `def Table(*c, **kwargs)` + Creates a table + +- `def TableFromLists(header_data, body_data, footer_data, header_cell_render, body_cell_render, footer_cell_render, cls, sortable, **kwargs)` + Creates a Table from a list of header data and a list of lists of body data + +- `def TableFromDicts(header_data, body_data, footer_data, header_cell_render, body_cell_render, footer_cell_render, cls, sortable, **kwargs)` + Creates a Table from a list of header data and a list of dicts of body data + +- `def apply_classes(html_str, class_map, class_map_mods)` + Apply classes to html string + +- `def render_md(md_content, class_map, class_map_mods)` + Renders markdown using mistletoe and lxml + +- `def get_franken_renderer(img_dir)` + Create a renderer class with the specified img_dir + +- `def ThemePicker(color, radii, shadows, font, mode, cls, custom_themes)` + Theme picker component with configurable sections + +- `def LightboxContainer(*lightboxitem, **kwargs)` + Lightbox container that will hold `LightboxItems` + +- `def LightboxItem(*c, **kwargs)` + Anchor tag with appropriate structure to go inside a `LightBoxContainer` +"""FrankenUI Playground Example built with MonsterUI (original design by ShadCN)""" + +from fasthtml.common import * +from monsterui.all import * +from fasthtml.svg import * + +app, rt = fast_app(hdrs=Theme.blue.headers()) + +preset_options = ["Grammatical Standard English", "Summarize for a 2nd grader", + "Text to command","Q&A","English to other languages","Parse unstructured data", + "Classification","Natural language to Python","Explain code","Chat","More examples"] + +def playground_navbar(): + save_modal = Modal( + ModalTitle("Save preset"), + P("This will save the current playground state as a preset which you can access later or share with others.",cls=("mt-1.5", TextPresets.muted_sm)), + LabelInput("Name", id="name"), + LabelInput("Description", id="description"), + ModalCloseButton("Save", cls=ButtonT.primary), + id="save") + + share_dd = Div(cls="space-y-6 p-4")( + H3("Share preset"), + P("Anyone who has this link and an OpenAI account will be able to view this.", cls=TextPresets.muted_sm), + Div(Input(value="https://platform.openai.com/playground/p/7bbKYQvsVkNmVb8NGcdUOLae?model=text-davinci-003", readonly=True), + Button(UkIcon('copy'), cls=(ButtonT.primary, "uk-drop-close",'mt-4')))) + + rnav = ( + Select(*Options(*preset_options), name='preset', optgroup_label="Examples", + placeholder='Load a preset', searchable=True, cls='h-9 w-[200px] lg:w-[300px]'), + Button("Save", cls=ButtonT.secondary, data_uk_toggle="#save"),save_modal, + Button("View Code", cls=ButtonT.secondary), + Button("Share", cls=ButtonT.secondary),DropDownNavContainer(share_dd), + Button(UkIcon(icon="ellipsis"), cls=ButtonT.secondary), + DropDownNavContainer( + Li(A("Content filter preferences")), + NavDividerLi(), + Li(A("Delete preset", cls="text-destructive")), + uk_dropdown="mode: click")) + + return NavBar(*rnav, brand=H4('Playground')) + +rsidebar = NavContainer( + Select( + Optgroup(map(Option,("text-davinci-003", "text-curie-001", "text-babbage-001", "text-ada-001")),label='GPT-3'), + Optgroup(map(Option,("code-davinci-002", "code-cushman-001")),label='Codex'), + label="Model", + searchable=True), + LabelRange(label='Temperature', value='12'), + LabelRange(label='Maximum Length', value='80'), + LabelRange(label='Top P', value='40'), + cls='space-y-6 mt-8') + +@rt +def index(): + navbar = playground_navbar() + main_content = Div( + Div(cls="flex-1")( + Textarea(cls="uk-textarea h-full p-4", placeholder="Write a tagline for an ice cream shop")), + cls="flex h-[700px] p-8 w-4/5") + + bottom_buttons = Div( + Button("Submit", cls=ButtonT.primary), + Button(UkIcon(icon="history"), cls=ButtonT.secondary), + cls="flex gap-x-2") + + return Title("Playground Example"),Div(navbar, Div(cls="flex w-full")(main_content, rsidebar), bottom_buttons) + +serve()"MonsterUI Scrollspy Example application" + +from fasthtml.common import * +from monsterui.all import * +import random + +# Using the "slate" theme with Highlight.js enabled +hdrs = Theme.slate.headers(highlightjs=True) +app, rt = fast_app(hdrs=hdrs) + +################################ +### Example Data and Content ### +################################ +products = [ + {"name": "Laptop", "price": "$999"}, + {"name": "Smartphone", "price": "$599"} +] + +code_example = """ +# Python Code Example +def greet(name): + return f"Hello, {name}!" + +print(greet("World")) +""" +testimonials = [ + {"name": "Alice", "feedback": "Great products and excellent customer service!"}, + {"name": "Bob", "feedback": "Fast shipping and amazing quality!"}, + {"name": "Charlie", "feedback": "Amazing experience! Will definitely buy again."}, + {"name": "Diana", "feedback": "Affordable prices and great variety!"}, + {"name": "Edward", "feedback": "Customer support was very helpful."}, + {"name": "Fiona", "feedback": "Loved the design and quality!"} +] + +# Team members +team = [ + {"name": "Isaac Flath", "role": "CEO"}, + {"name": "Benjamin Clavié", "role": "AI Researcher"}, + {"name": "Alexis Gallagher", "role": "ML Engineer"}, + {"name": "Hamel Husain", "role": "Data Scientist"}, + {"name": "Austin Huang", "role": "Software Engineer"}, + {"name": "Benjamin Warner", "role": "Product Manager"}, + {"name": "Jonathan Whitaker", "role": "UX Designer"}, + {"name": "Kerem Turgutlu", "role": "DevOps Engineer"}, + {"name": "Curtis Allan", "role": "DevOps Engineer"}, + {"name": "Audrey Roy Greenfeld", "role": "Security Analyst"}, + {"name": "Nathan Cooper", "role": "Full Stack Developer"}, + {"name": "Jeremy Howard", "role": "CTO"}, + {"name": "Wayde Gilliam", "role": "Cloud Architect"}, + {"name": "Daniel Roy Greenfeld", "role": "Blockchain Expert"}, + {"name": "Tommy Collins", "role": "AI Ethics Researcher"} +] + + +def ProductCard(p,img_id=1): + return Card( + PicSumImg(w=500, height=100, id=img_id), + DivFullySpaced(H4(p["name"]), P(Strong(p["price"], cls=TextT.sm))), + Button("Details", cls=(ButtonT.primary, "w-full"))) + +def TestimonialCard(t,img_id=1): + return Card( + DivLAligned(PicSumImg(w=50, h=50, cls='rounded-full', id=img_id), H4(t["name"])), + P(Q((t["feedback"])))) + + +def TeamCard(m,img_id=1): + return Card( + DivLAligned( + PicSumImg(w=50, h=50, cls='rounded-full', id=img_id), + Div(H4(m["name"]), P(m["role"]))), + DivRAligned( + UkIcon('twitter', cls='w-5 h-5'), + UkIcon('linkedin', cls='w-5 h-5'), + UkIcon('github', cls='w-5 h-5'), + cls=TextT.gray+'space-x-2' + ), + cls='p-3') + +################################ +### Navigation and Scrollspy ### +################################ + +scrollspy_links = ( + A("Welcome", href="#welcome-section"), + A("Products", href="#products-section"), + A("Testimonials", href="#testimonials-section"), + A("Team", href="#team-section"), + A("Code Example", href="#code-section")) +@rt +def index(): + def _Section(*c, **kwargs): return Section(*c, cls='space-y-3 my-48',**kwargs) + return Container( + NavBar( + *scrollspy_links, + brand=DivLAligned(H3("Scrollspy Demo!"),UkIcon('rocket',height=30,width=30)), + sticky=True, uk_scrollspy_nav=True, + scrollspy_cls=ScrollspyT.bold), + NavContainer( + *map(Li, scrollspy_links), + uk_scrollspy_nav=True, + sticky=True, + cls=(NavT.primary,'pt-20 px-5 pr-10')), + Container( + # Notice the ID of each section corresponds to the `scrollspy_links` dictionary + # So in scollspy `NavContainer` the `href` of each `Li` is the ID of the section + DivCentered( + H1("Welcome to the Store!"), + Subtitle("Explore our products and enjoy dynamic code examples."), + id="welcome-section"), + _Section(H2("Products"), + Grid(*[ProductCard(p,img_id=i) for i,p in enumerate(products)], cols_lg=2), + id="products-section"), + _Section(H2("Testimonials"), + Slider(*[TestimonialCard(t,img_id=i) for i,t in enumerate(testimonials)]), + id="testimonials-section"), + _Section(H2("Our Team"), + Grid(*[TeamCard(m,img_id=i) for i,m in enumerate(team)], cols_lg=2, cols_max=3), + id="team-section"), + _Section(H2("Code Example"), + CodeBlock(code_example, lang="python"), + id="code-section")), + cls=(ContainerT.xl,'uk-container-expand')) + +serve()"""FrankenUI Mail Example built with MonsterUI (original design by ShadCN)""" + +from fasthtml.common import * +from monsterui.all import * +from fasthtml.svg import * +import pathlib, json +from datetime import datetime + +app, rt = fast_app(hdrs=Theme.blue.headers()) + +sidebar_group1 = (('home', 'Inbox', '128'), ('file-text', 'Drafts', '9'), (' arrow-up-right', 'Sent', ''), + ('ban', 'Junk', '23'), ('trash', 'Trash', ''), ('folder', 'Archive', '')) + +sidebar_group2 = (('globe','Social','972'),('info','Updates','342'),('messages-square','Forums','128'), + ('shopping-cart','Shopping','8'),('shopping-bag','Promotions','21'),) + +def MailSbLi(icon, title, cnt): + return Li(A(DivLAligned(Span(UkIcon(icon)),Span(title),P(cnt, cls=TextPresets.muted_sm)),href='#', cls='hover:bg-secondary p-4')) + +sidebar = NavContainer( + NavHeaderLi(H3("Email"), cls='p-3'), + Li(Select(map(Option, ('alicia@example.com','alicia@gmail.com', 'alicia@yahoo.com')))), + *[MailSbLi(i, t, c) for i, t, c in sidebar_group1], + Li(Hr()), + *[MailSbLi(i, t, c) for i, t, c in sidebar_group2], + cls='mt-3') + +mail_data = json.load(open(pathlib.Path('data/mail.json'))) + +def format_date(date_str): + date_obj = datetime.fromisoformat(date_str) + return date_obj.strftime("%Y-%m-%d %I:%M %p") + +def MailItem(mail): + cls_base = 'relative rounded-lg border border-border p-3 text-sm hover:bg-secondary space-y-2' + cls = f"{cls_base} {'bg-muted' if mail == mail_data[0] else ''} {'tag-unread' if not mail['read'] else 'tag-mail'}" + + return Li( + DivFullySpaced( + DivLAligned( + Strong(mail['name']), + Span(cls='flex h-2 w-2 rounded-full bg-blue-600') if not mail['read'] else ''), + Time(format_date(mail['date']), cls='text-xs')), + Small(mail['subject'], href=f"#mail-{mail['id']}"), + Div(mail['text'][:100] + '...', cls=TextPresets.muted_sm), + DivLAligned( + *[Label(A(label, href='#'), cls='uk-label-primary' if label == 'work' else '') for label in mail['labels']]), + cls=cls) + +def MailList(mails): return Ul(cls='js-filter space-y-2 p-4 pt-0')(*[MailItem(mail) for mail in mails]) + +def MailContent(): + return Div(cls='flex flex-col',uk_filter="target: .js-filter")( + Div(cls='flex px-4 py-2 ')( + H3('Inbox'), + TabContainer(Li(A("All Mail",href='#', role='button'),cls='uk-active', uk_filter_control="filter: .tag-mail"), + Li(A("Unread",href='#', role='button'), uk_filter_control="filter: .tag-unread"), + alt=True, cls='ml-auto max-w-40', )), + Div(cls='flex flex-1 flex-col')( + Div(cls='p-4')( + Div(cls='uk-inline w-full')( + Span(cls='uk-form-icon text-muted-foreground')(UkIcon('search')), + Input(placeholder='Search'))), + Div(cls='flex-1 overflow-y-auto max-h-[600px]')(MailList(mail_data)))) + +def IconNavItem(*d): return [Li(A(UkIcon(o[0],uk_tooltip=o[1]))) for o in d] +def IconNav(*c,cls=''): return Ul(cls=f'uk-iconnav {cls}')(*c) + +def MailDetailView(mail): + top_icons = [('folder','Archive'), ('ban','Move to junk'), ('trash','Move to trash')] + reply_icons = [('reply','Reply'), ('reply','Reply all'), ('forward','Forward')] + dropdown_items = ['Mark as unread', 'Star read', 'Add Label', 'Mute Thread'] + + return Container( + DivFullySpaced( + DivLAligned( + DivLAligned(*[UkIcon(o[0],uk_tooltip=o[1]) for o in top_icons]), + Div(UkIcon('clock', uk_tooltip='Snooze'), cls='pl-2'), + cls='space-x-2 divide-x divide-border'), + DivLAligned( + *[UkIcon(o[0],uk_tooltip=o[1]) for o in reply_icons], + Div(UkIcon('ellipsis-vertical',button=True)), + DropDownNavContainer(*map(lambda x: Li(A(x)), dropdown_items)))), + DivLAligned( + Span(mail['name'][:2], cls='flex h-10 w-10 items-center justify-center rounded-full bg-muted'), + Div(Strong(mail['name']), + Div(mail['subject']), + DivLAligned(P('Reply-To:'), A(mail['email'], href=f"mailto:{mail['email']}"), cls='space-x-1'), + P(Time(format_date(mail['date']))), + cls='space-y-1'+TextT.sm), + cls='m-4 space-x-4'), + DividerLine(), + P(mail['text'], cls=TextT.sm +'p-4'), + DividerLine(), + Div(TextArea(id='message', placeholder=f"Reply {mail['name']}"), + DivFullySpaced( + LabelSwitch('Mute this thread',id='mute'), + Button('Send', cls=ButtonT.primary)), + cls='space-y-4')) + +@rt +def index(): + return Title("Mail Example"),Container( + Grid(Div(sidebar, cls='col-span-1'), + Div(MailContent(), cls='col-span-2'), + Div(MailDetailView(mail_data[0]), cls='col-span-2'), + cols_sm=1, cols_md=1, cols_lg=5, cols_xl=5, + gap=0, cls='flex-1'), + cls=('flex', ContainerT.xl)) + +serve()"""FrankenUI Forms Example built with MonsterUI (original design by ShadCN)""" + + +from fasthtml.common import * +from monsterui.all import * +from fasthtml.svg import * + +app, rt = fast_app(hdrs=Theme.blue.headers()) + +def HelpText(c): return P(c,cls=TextPresets.muted_sm) + +def heading(): + return Div(cls="space-y-5")( + H2("Settings"), + Subtitle("Manage your account settings and set e-mail preferences."), + DividerSplit()) + + +sidebar = NavContainer( + *map(lambda x: Li(A(x)), ("Profile", "Account", "Appearance", "Notifications", "Display")), + uk_switcher="connect: #component-nav; animation: uk-animation-fade", + cls=(NavT.secondary,"space-y-4 p-4 w-1/5")) + + +def FormSectionDiv(*c, cls='space-y-2', **kwargs): return Div(*c, cls=cls, **kwargs) + +def FormLayout(title, subtitle, *content, cls='space-y-3 mt-4'): return Container(Div(H3(title), Subtitle(subtitle), DividerLine(), Form(*content, cls=cls))) + +def profile_form(): + content = (FormSectionDiv( + LabelInput("Username", placeholder='sveltecult', id='username'), + HelpText("This is your public display name. It can be your real name or a pseudonym. You can only change this once every 30 days.")), + FormSectionDiv( + LabelSelect( + Option("Select a verified email to display", value="", selected=True, disabled=True), + *[Option(o, value=o) for o in ('m@example.com', 'm@yahoo.com', 'm@cloud.com')], + label="Email", id="email"), + HelpText("You can manage verified email addresses in your email settings.")), + FormSectionDiv( + LabelTextArea("Bio", id="bio", placeholder="Tell us a little bit about yourself"), + HelpText("You can @mention other users and organizations to link to them."), + P("String must contain at least 4 character(s)", cls="text-destructive")), + FormSectionDiv( + FormLabel("URLs"), + HelpText("Add links to your website, blog, or social media profiles."), + Input(value="https://www.franken-ui.dev"), + Input(value="https://github.com/sveltecult/franken-ui"), + Button("Add URL")), + Button('Update profile', cls=ButtonT.primary)) + + return FormLayout('Profile', 'This is how others will see you on the site.', *content) + +def account_form(): + content = ( + FormSectionDiv( + LabelInput("Name", placeholder="Your name", id="name"), + HelpText("This is the name that will be displayed on your profile and in emails.")), + FormSectionDiv( + LabelInput("Date of Birth", type="date", placeholder="Pick a date", id="date_of_birth"), + HelpText("Your date of birth is used to calculate your age.")), + FormSectionDiv( + LabelSelect(*Options("Select a language", "English", "French", "German", "Spanish", "Portuguese", selected_idx=1, disabled_idxs={0}), + label='Language', id="language"), + HelpText("This is the language that will be used in the dashboard.")), + Button('Update profile', cls=ButtonT.primary)) + + return FormLayout('Account', 'Update your account settings. Set your preferred language and timezone.', *content) + +def appearance_form(): + def theme_item(bg_color, content_bg, text_bg): + common_content = f"space-y-2 rounded-md {content_bg} p-2 shadow-sm" + item_row = lambda: Div(cls=f"flex items-center space-x-2 {common_content}")( + Div(cls=f"h-4 w-4 rounded-full {text_bg}"), + Div(cls=f"h-2 w-[100px] rounded-lg {text_bg}")) + + return Div(cls=f"space-y-2 rounded-sm {bg_color} p-2")( + Div(cls=common_content)( + Div(cls=f"h-2 w-[80px] rounded-lg {text_bg}"), + Div(cls=f"h-2 w-[100px] rounded-lg {text_bg}")), + item_row(), + item_row()) + + common_toggle_cls = "block cursor-pointer items-center rounded-md border-2 border-muted p-1 ring-ring" + + content = ( + FormSectionDiv( + LabelSelect(*Options('Select a font family', 'Inter', 'Geist', 'Open Sans', selected_idx=2, disabled_idxs={0}), + label='Font Family', id='font_family'), + HelpText("Set the font you want to use in the dashboard.")), + FormSectionDiv( + FormLabel("Theme"), + HelpText("Select the theme for the dashboard."), + Grid( + A(id="theme-toggle-light", cls=common_toggle_cls)(theme_item("bg-[#ecedef]", "bg-white", "bg-[#ecedef]")), + A(id="theme-toggle-dark", cls=f"{common_toggle_cls} bg-popover")(theme_item("bg-slate-950", "bg-slate-800", "bg-slate-400")), + cols_max=2,cls=('max-w-md','gap-8'))), + Button('Update preferences', cls=ButtonT.primary)) + + return FormLayout('Appearance', 'Customize the appearance of the app. Automatically switch between day and night themes.', *content) + + +notification_items = [ + {"title": "Communication emails", "description": "Receive emails about your account activity.", "checked": False, "disabled": False}, + {"title": "Marketing emails", "description": "Receive emails about new products, features, and more.", "checked": False, "disabled": False}, + {"title": "Social emails", "description": "Receive emails for friend requests, follows, and more.", "checked": True, "disabled": False}, + {"title": "Security emails", "description": "Receive emails about your account activity and security.", "checked": True, "disabled": True}] + +def notifications_form(): + def RadioLabel(label): return DivLAligned(Radio(name="notification", checked=(label=="Nothing")), FormLabel(label)) + + def NotificationCard(item): + return Card( + Div(cls="space-y-0.5")( + FormLabel(Strong(item['title'], cls=TextT.sm), + HelpText(item['description'])))) + content = Div( + FormSectionDiv( + FormLabel("Notify me about"), + *map(RadioLabel, ["All new messages", "Direct messages and mentions", "Nothing"])), + Div( + H4("Email Notifications", cls="mb-4"), + Grid(*map(NotificationCard, notification_items), cols=1)), + LabelCheckboxX("Use different settings for my mobile devices", id="notification_mobile"), + HelpText("You can manage your mobile notifications in the mobile settings page."), + Button('Update notifications', cls=ButtonT.primary)) + + return FormLayout('Notifications', 'Configure how you receive notifications.', *content) + +def display_form(): + content = ( + Div(cls="space-y-2")( + Div(cls="mb-4")( + H5("Sidebar"), + Subtitle("Select the items you want to display in the sidebar.")), + *[Div(CheckboxX(id=f"display_{i}", checked=i in [0, 1, 2]),FormLabel(label)) + for i, label in enumerate(["Recents", "Home", "Applications", "Desktop", "Downloads", "Documents"])]), + Button('Update display', cls=ButtonT.primary)) + return FormLayout('Display', 'Turn items on or off to control what\'s displayed in the app.', *content) + +@rt +def index(): + return Title("Forms Example"),Container( + heading(), + Div(cls="flex gap-x-12")( + sidebar, + Ul(id="component-nav", cls="uk-switcher max-w-2xl")( + Li(cls="uk-active")(profile_form(), + *map(Li, [account_form(), appearance_form(), notifications_form(), display_form()]))))) + +serve()"""FrankenUI Tasks Example built with MonsterUI (original design by ShadCN)""" + +from fasthtml.common import * +from monsterui.all import * +from fasthtml.svg import * +import json + +app, rt = fast_app(hdrs=Theme.blue.headers()) + +def LAlignedCheckTxt(txt): return DivLAligned(UkIcon(icon='check'), P(txt, cls=TextPresets.muted_sm)) + +with open('data/status_list.json', 'r') as f: data = json.load(f) +with open('data/statuses.json', 'r') as f: statuses = json.load(f) + +def _create_tbl_data(d): + return {'Done': d['selected'], 'Task': d['id'], 'Title': d['title'], + 'Status' : d['status'], 'Priority': d['priority'] } + +data = [_create_tbl_data(d) for d in data] +page_size = 15 +current_page = 0 +paginated_data = data[current_page*page_size:(current_page+1)*page_size] + +priority_dd = [{'priority': "low", 'count': 36 }, {'priority': "medium", 'count': 33 }, {'priority': "high", 'count': 31 }] + +status_dd = [{'status': "backlog", 'count': 21 },{'status': "todo", 'count': 21 },{'status': "progress", 'count': 20 },{'status': "done",'count': 19 },{'status': "cancelled", 'count': 19 }] + +def create_hotkey_li(hotkey): return NavCloseLi(A(DivFullySpaced(hotkey[0], Span(hotkey[1], cls=TextPresets.muted_sm)))) + +hotkeys_a = (('Profile','⇧⌘P'),('Billing','⌘B'),('Settings','⌘S'),('New Team','')) +hotkeys_b = (('Logout',''), ) + +avatar_opts = DropDownNavContainer( + NavHeaderLi(P('sveltecult'),NavSubtitle('leader@sveltecult.com')), + NavDividerLi(), + *map(create_hotkey_li, hotkeys_a), + NavDividerLi(), + *map(create_hotkey_li, hotkeys_b),) + +def CreateTaskModal(): + return Modal( + Div(cls='p-6')( + ModalTitle('Create Task'), + P('Fill out the information below to create a new task', cls=TextPresets.muted_sm), + Br(), + Form(cls='space-y-6')( + Grid(Div(Select(*map(Option,('Documentation', 'Bug', 'Feature')), label='Task Type', id='task_type')), + Div(Select(*map(Option,('In Progress', 'Backlog', 'Todo', 'Cancelled', 'Done')), label='Status', id='task_status')), + Div(Select(*map(Option, ('Low', 'Medium', 'High')), label='Priority', id='task_priority'))), + TextArea(label='Title', placeholder='Please describe the task that needs to be completed'), + DivRAligned( + ModalCloseButton('Cancel', cls=ButtonT.ghost), + ModalCloseButton('Submit', cls=ButtonT.primary), + cls='space-x-5'))), + id='TaskForm') + +page_heading = DivFullySpaced(cls='space-y-2')( + Div(cls='space-y-2')( + H2('Welcome back!'),P("Here's a list of your tasks for this month!", cls=TextPresets.muted_sm)), + Div(DiceBearAvatar("sveltcult",8,8),avatar_opts)) + +table_controls =(Input(cls='w-[250px]',placeholder='Filter task'), + Button("Status"), + DropDownNavContainer(map(NavCloseLi,[A(DivFullySpaced(P(a['status']), P(a['count'])),cls='capitalize') for a in status_dd])), + Button("Priority"), + DropDownNavContainer(map(NavCloseLi,[A(DivFullySpaced(LAlignedCheckTxt(a['priority']), a['count']),cls='capitalize') for a in priority_dd])), + Button("View"), + DropDownNavContainer(map(NavCloseLi,[A(LAlignedCheckTxt(o)) for o in ['Title','Status','Priority']])), + Button('Create Task',cls=(ButtonT.primary, TextPresets.bold_sm), data_uk_toggle="target: #TaskForm")) + +def task_dropdown(): + return Div(Button(UkIcon('ellipsis')), + DropDownNavContainer( + map(NavCloseLi,[ + *map(A,('Edit', 'Make a copy', 'Favorite')), + A(DivFullySpaced(*[P(o, cls=TextPresets.muted_sm) for o in ('Delete', '⌘⌫')]))]))) +def header_render(col): + match col: + case "Done": return Th(CheckboxX(), shrink=True) + case 'Actions': return Th("", shrink=True) + case _: return Th(col, expand=True) + +def cell_render(col, val): + def _Td(*args,cls='', **kwargs): return Td(*args, cls=f'p-2 {cls}',**kwargs) + match col: + case "Done": return _Td(shrink=True)(CheckboxX(selected=val)) + case "Task": return _Td(val, cls='uk-visible@s') # Hide on small screens + case "Title": return _Td(val, cls='font-medium', expand=True) + case "Status" | "Priority": return _Td(cls='uk-visible@m uk-text-nowrap capitalize')(Span(val)) + case "Actions": return _Td(task_dropdown(), shrink=True) + case _: raise ValueError(f"Unknown column: {col}") + +task_columns = ["Done", 'Task', 'Title', 'Status', 'Priority', 'Actions'] + +tasks_table = Div(cls='mt-4')( + TableFromDicts( + header_data=task_columns, + body_data=paginated_data, + body_cell_render=cell_render, + header_cell_render=header_render, + sortable=True, + cls=(TableT.responsive, TableT.sm, TableT.divider))) + + +def footer(): + total_pages = (len(data) + page_size - 1) // page_size + return DivFullySpaced( + Div('1 of 100 row(s) selected.', cls=TextPresets.muted_sm), + DivLAligned( + DivCentered(f'Page {current_page + 1} of {total_pages}', cls=TextT.sm), + DivLAligned(*[UkIconLink(icon=i, button=True) for i in ('chevrons-left', 'chevron-left', 'chevron-right', 'chevrons-right')]))) + +tasks_ui = Div(DivFullySpaced(DivLAligned(table_controls), cls='mt-8'), tasks_table, footer()) + +@rt +def index(): return Container(page_heading, tasks_ui, CreateTaskModal()) + +serve()"""FrankenUI Cards Example built with MonsterUI (original design by ShadCN)""" + +from fasthtml.common import * +from fasthtml.components import Uk_input_tag +from fasthtml.svg import * +from monsterui.all import * +import calendar +from datetime import datetime + +app, rt = fast_app(hdrs=Theme.blue.headers()) + +CreateAccount = Card( + Grid(Button(DivLAligned(UkIcon('github'),Div('Github'))),Button('Google')), + DividerSplit("OR CONTINUE WITH", text_cls=TextPresets.muted_sm), + LabelInput('Email', id='email', placeholder='m@example.com'), + LabelInput('Password', id='password',placeholder='Password', type='Password'), + header=(H3('Create an Account'),Subtitle('Enter your email below to create your account')), + footer=Button('Create Account',cls=(ButtonT.primary,'w-full'))) + +PaypalSVG_data = "M7.076 21.337H2.47a.641.641 0 0 1-.633-.74L4.944.901C5.026.382 5.474 0 5.998 0h7.46c2.57 0 4.578.543 5.69 1.81 1.01 1.15 1.304 2.42 1.012 4.287-.023.143-.047.288-.077.437-.983 5.05-4.349 6.797-8.647 6.797h-2.19c-.524 0-.968.382-1.05.9l-1.12 7.106zm14.146-14.42a3.35 3.35 0 0 0-.607-.541c-.013.076-.026.175-.041.254-.93 4.778-4.005 7.201-9.138 7.201h-2.19a.563.563 0 0 0-.556.479l-1.187 7.527h-.506l-.24 1.516a.56.56 0 0 0 .554.647h3.882c.46 0 .85-.334.922-.788.06-.26.76-4.852.816-5.09a.932.932 0 0 1 .923-.788h.58c3.76 0 6.705-1.528 7.565-5.946.36-1.847.174-3.388-.777-4.471z" +AppleSVG_data = "M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701" +Card1Svg = Svg(viewBox="0 0 24 24", fill="none", stroke="currentColor", stroke_linecap="round", stroke_linejoin="round", stroke_width="2", cls="h-6 w-6 mr-1")(Rect(width="20", height="14", x="2", y="5", rx="2"),Path(d="M2 10h20")) +PaypalSvg = Svg(role="img", viewBox="0 0 24 24", cls="h-6 w-6 mr-1")(Path(d=PaypalSVG_data, fill="currentColor")), +AppleSvg = Svg(role="img", viewBox="0 0 24 24", cls="h-6 w-6 mr-1")(Path(d=AppleSVG_data, fill="currentColor")) + +PaymentMethod = Card( + Grid(Button(DivCentered(Card1Svg, "Card"), cls='h-20 border-2 border-primary'), + Button(DivCentered(PaypalSvg, "PayPal"), cls='h-20'), + Button(DivCentered(AppleSvg, "Apple"), cls='h-20')), + Form(LabelInput('Name', id='name', placeholder='John Doe'), + LabelInput('Card Number', id='card_number', placeholder='m@example.com'), + Grid(LabelSelect(*Options(*calendar.month_name[1:],selected_idx=0),label='Expires',id='expire_month'), + LabelSelect(*Options(*range(2024,2030),selected_idx=0), label='Year', id='expire_year'), + LabelInput('CVV', id='cvv',placeholder='CVV', cls='mt-0'))), + header=(H3('Payment Method'),Subtitle('Add a new payment method to your account.'))) + +area_opts = ('Team','Billing','Account','Deployment','Support') +severity_opts = ('Severity 1 (Highest)', 'Severity 2', 'Severity 3', 'Severity 4 (Lowest)') +ReportIssue = Card( + Grid(Div(LabelSelect(*Options(*area_opts), label='Area', id='area')), + Div(LabelSelect(*Options(*severity_opts),label='Severity',id='area'))), + LabelInput( label='Subject', id='subject', placeholder='I need help with'), + LabelTextArea( label='Description', id='description',placeholder='Please include all information relevant to your issue'), + Div(FormLabel('Tags', fr='#tags'), + Uk_input_tag(name="Tags",state="danger", value="Spam,Invalid", uk_cloak=True, id='tags')), + header=(H3('Report Issue'),Subtitle('What area are you having problems with?')), + footer = DivFullySpaced(Button('Cancel'), Button(cls=ButtonT.primary)('Submit'))) + +monster_desc ="Python-first beautifully designed components because you deserve to focus on features that matter and your app deserves to be beautiful from day one." +MonsterUI = Card(H4("Monster UI"), + Subtitle(monster_desc), + DivLAligned( + Div("Python"), + DivLAligned(UkIcon('star'),Div("20k"), cls='space-x-1'), + Div(datetime.now().strftime("%B %d, %Y")), + cls=('space-x-4',TextPresets.muted_sm))) + +def CookieTableRow(heading, description, active=False): + return Tr(Td(H5(heading)), + Td(P(description, cls=TextPresets.muted_sm)), + Td(Switch(checked=active))) + +CookieSettings = Card( + Table(Tbody( + CookieTableRow('Strictly Necessary', 'These cookies are essential in order to use the website and use its features.', True), + CookieTableRow('Functional Cookies', 'These cookies allow the website to provide personalized functionality.'), + CookieTableRow('Performance Cookies', 'These cookies help to improve the performance of the website.'))), + header=(H4('Cookie Settings'),Subtitle('Manage your cookie settings here.')), + footer=Button('Save Preferences', cls=(ButtonT.primary, 'w-full'))) + +team_members = [("Sofia Davis", "m@example.com", "Owner"),("Jackson Lee", "p@example.com", "Member"),] +def TeamMemberRow(name, email, role): + return DivFullySpaced( + DivLAligned( + DiceBearAvatar(name, 10,10), + Div(P(name, cls=(TextT.sm, TextT.medium)), + P(email, cls=TextPresets.muted_sm))), + Button(role, UkIcon('chevron-down', cls='ml-4')), + DropDownNavContainer(map(NavCloseLi, [ + A(Div('Viewer', NavSubtitle('Can view and comment.'))), + A(Div('Developer', NavSubtitle('Can view, comment and edit.'))), + A(Div('Billing', NavSubtitle('Can view, comment and manage billing.'))), + A(Div('Owner', NavSubtitle('Admin-level access to all resources.')))]))) + +TeamMembers = Card(*[TeamMemberRow(*member) for member in team_members], + header = (H4('Team Members'),Subtitle('Invite your team members to collaborate.'))) + +access_roles = ("Read and write access", "Read-only access") +team_members = [("Olivia Martin", "m@example.com", "Read and write access"), + ("Isabella Nguyen", "b@example.com", "Read-only access"), + ("Sofia Davis", "p@example.com", "Read-only access")] + +def TeamMemberRow(name, email, role): + return DivFullySpaced( + DivLAligned(DiceBearAvatar(name, 10,10), + Div(P(name, cls=(TextT.sm, TextT.medium)), + P(email, cls=TextPresets.muted_sm))), + Select(*Options(*access_roles, selected_idx=access_roles.index(role)))) + +ShareDocument = Card( + DivLAligned(Input(value='http://example.com/link/to/document'),Button('Copy link', cls='whitespace-nowrap')), + Divider(), + H4('People with access', cls=TextPresets.bold_sm), + *[TeamMemberRow(*member) for member in team_members], + header = (H4('Share this document'),Subtitle('Anyone with the link can view this document.'))) + +DateCard = Card(Button('Jan 20, 2024 - Feb 09, 2024')) + +section_content =(('bell','Everything',"Email digest, mentions & all activity."), + ('user',"Available","Only mentions and comments"), + ('ban', "Ignoring","Turn of all notifications")) + +def NotificationRow(icon, name, desc): + return Li(cls='-mx-1')(A(DivLAligned(UkIcon(icon),Div(P(name),P(desc, cls=TextPresets.muted_sm))))) + +Notifications = Card( + NavContainer( + *[NotificationRow(*row) for row in section_content], + cls=NavT.secondary), + header = (H4('Notification'),Subtitle('Choose what you want to be notified about.')), + body_cls='pt-0') + +TeamCard = Card( + DivLAligned( + DiceBearAvatar("Isaac Flath", h=24, w=24), + Div(H3("Isaac Flath"), P("Library Creator"))), + footer=DivFullySpaced( + DivHStacked(UkIcon("map-pin", height=16), P("Alexandria, VA")), + DivHStacked(*(UkIconLink(icon, height=16) for icon in ("mail", "linkedin", "github")))), + cls=CardT.hover) + +@rt +def index(): + return Title("Cards Example"),Container(Grid( + *map(Div,( + Div(PaymentMethod,CreateAccount, TeamCard, cls='space-y-4'), + Div(TeamMembers, ShareDocument,DateCard,Notifications, cls='space-y-4'), + Div(ReportIssue,MonsterUI,CookieSettings, cls='space-y-4'))), + cols_md=1, cols_lg=2, cols_xl=3)) + +serve()"""FrankenUI Dashboard Example built with MonsterUI (original design by ShadCN)""" + +from fasthtml.common import * # Bring in all of fasthtml +import fasthtml.common as fh # Used to get unstyled components +from monsterui.all import * # Bring in all of monsterui, including shadowing fasthtml components with styled components +from fasthtml.svg import * +import numpy as np +import plotly.express as px +import pandas as pd +import numpy as np + +app, rt = fast_app(hdrs=Theme.blue.headers()) + +def generate_chart(num_points=30): + df = pd.DataFrame({ + 'Date': pd.date_range('2024-01-01', periods=num_points), + 'Revenue': np.random.normal(100, 10, num_points).cumsum(), + 'Users': np.random.normal(80, 8, num_points).cumsum(), + 'Growth': np.random.normal(60, 6, num_points).cumsum()}) + + fig = px.line(df, x='Date', y=['Revenue', 'Users', 'Growth'], template='plotly_white', line_shape='spline') + + fig.update_traces(mode='lines+markers') + fig.update_layout( + margin=dict(l=20, r=20, t=20, b=20), hovermode='x unified', + showlegend=True, legend=dict(orientation='h', yanchor='bottom', y=1.02, xanchor='right', x=1), + plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)', + xaxis=dict(showgrid=True, gridwidth=1, gridcolor='rgba(0,0,0,0.1)'), + yaxis=dict(showgrid=True, gridwidth=1, gridcolor='rgba(0,0,0,0.1)')) + + return fig.to_html(include_plotlyjs=True, full_html=False, config={'displayModeBar': False}) + +def InfoCard(title, value, change): return Card(H3(value),P(change, cls=TextPresets.muted_sm), header = H4(title)) + +rev = InfoCard("Total Revenue", "$45,231.89", "+20.1% from last month") +sub = InfoCard("Subscriptions", "+2350", "+180.1% from last month") +sal = InfoCard("Sales", "+12,234", "+19% from last month") +act = InfoCard("Active Now", "+573", "+201 since last hour") + +info_card_data = [("Total Revenue", "$45,231.89", "+20.1% from last month"), + ("Subscriptions", "+2350", "+180.1% from last month"), + ("Sales", "+12,234", "+19% from last month"), + ("Active Now", "+573", "+201 since last hour")] + +top_info_row = Grid(*[InfoCard(*row) for row in info_card_data]) + +def AvatarItem(name, email, amount): + return DivFullySpaced( + DivLAligned( + DiceBearAvatar(name, 9,9), + Div(Strong(name, cls=TextT.sm), + Address(A(email,href=f'mailto:{email}')))), + fh.Data(amount, cls="ml-auto font-medium", value=amount[2:])) + +recent_sales = Card( + Div(cls="space-y-8")( + *[AvatarItem(n,e,d) for (n,e,d) in ( + ("Olivia Martin", "olivia.martin@email.com", "+$1,999.00"), + ("Jackson Lee", "jackson.lee@email.com", "+$39.00"), + ("Isabella Nguyen", "isabella.nguyen@email.com", "+$299.00"), + ("William Kim", "will@email.com", "+$99.00"), + ("Sofia Davis", "sofia.davis@email.com", "+$39.00"))]), + header=Div(H3("Recent Sales"),Subtitle("You made 265 sales this month.")), + cls='col-span-3') + +teams = [["Alicia Koch"],['Acme Inc', 'Monster Inc.'],['Create a Team']] + +opt_hdrs = ["Personal", "Team", ""] + +team_dropdown = Select( + Optgroup(Option(A("Alicia Koch")), label="Personal Account"), + Optgroup(Option(A("Acme Inc")), Option(A("Monster Inc.")), label="Teams"), + Option(A("Create a Team")), + cls='flex items-center') + +hotkeys = [('Profile','⇧⌘P'),('Billing','⌘B'),('Settings','⌘S'),('New Team', ''), ('Logout', '')] + +def NavSpacedLi(t,s): return NavCloseLi(A(DivFullySpaced(P(t),P(s,cls=TextPresets.muted_sm)))) + +avatar_dropdown = Div( + DiceBearAvatar('Alicia Koch',8,8), + DropDownNavContainer( + NavHeaderLi('sveltecult',NavSubtitle("leader@sveltecult.com")), + *[NavSpacedLi(*hk) for hk in hotkeys],)) + +top_nav = NavBar( + team_dropdown, *map(A, ["Overview", "Customers", "Products", "Settings"]), + brand=DivLAligned(avatar_dropdown, Input(placeholder='Search'))) + +@rt +def index(): + return Title("Dashboard Example"), Container( + top_nav, + H2('Dashboard'), + TabContainer( + Li(A("Overview"),cls='uk-active'), + *map(lambda x: Li(A(x)), ["Analytics", "Reports", "Notifications"]), + alt=True), + top_info_row, + Grid( + Card(Safe(generate_chart(100)), cls='col-span-4'), + recent_sales, + gap=4,cols_xl=7,cols_lg=7,cols_md=1,cols_sm=1,cols_xs=1), + cls=('space-y-4', ContainerT.xl)) + +serve()"""MonsterUI Help Desk Example - Professional Dashboard with DaisyUI components""" +from fasthtml.common import * +from monsterui.all import * +from datetime import datetime + +app, rt = fast_app(hdrs=Theme.blue.headers(daisy=True)) + +def TicketSteps(step): + return Steps( + LiStep("Submitted", data_content="📝", + cls=StepT.success if step > 0 else StepT.primary if step == 0 else StepT.neutral), + LiStep("In Review", data_content="🔎", + cls=StepT.success if step > 1 else StepT.primary if step == 1 else StepT.neutral), + LiStep("Processing", data_content="⚙️", + cls=StepT.success if step > 2 else StepT.primary if step == 2 else StepT.neutral), + LiStep("Resolved", data_content="✅", + cls=StepT.success if step > 3 else StepT.primary if step == 3 else StepT.neutral), + cls="w-full") + +def StatusBadge(status): + styles = {'high': AlertT.error, 'medium': AlertT.warning,'low': AlertT.info} + alert_type = styles.get(status, AlertT.info) + return Alert(f"{status.title()} Priority", cls=(alert_type,"w-32 shadow-sm")) + +def TicketCard(id, title, description, status, step, department): + return Card( + CardHeader( + DivFullySpaced( + Div(H3(f"#{id}", cls=TextT.muted), + H4(title), + cls='space-y-2'), + StatusBadge(status))), + CardBody( + P(description, cls=(TextT.muted, "mb-6")), + DividerSplit(cls="my-6"), + TicketSteps(step), + DividerSplit(cls="my-6"), + DivFullySpaced( + Div(Strong("Department"), + P(department), + cls=('space-y-3', TextPresets.muted_sm)), + Div(Strong("Last Updated"), + P(Time(datetime.now().strftime('%b %d, %H:%M'))), + cls=('space-y-3', TextPresets.muted_sm)), + Button("View Details", cls=ButtonT.primary), + cls='mt-6')), + cls=CardT.hover) + +def NewTicketModal(): + return Modal( + ModalHeader(H3("Create New Support Ticket")), + ModalBody( + Alert( + DivLAligned(UkIcon("info"), Span("Please provide as much detail as possible to help us assist you quickly.")), + cls=(AlertT.info,"mb-4")), + Form( + Grid(LabelInput("Title", id="title", placeholder="Brief description of your issue"), + LabelSelect(Options("IT Support", "HR", "Facilities", "Finance"), label="Department", id="department")), + LabelSelect(Options("Low", "Medium", "High"), label="Priority Level", id="priority"), + LabelTextArea("Description", id="description", placeholder="Please provide detailed information about your issue"), + DivRAligned( + Button("Cancel", cls=ButtonT.ghost, data_uk_toggle="target: #new-ticket"), + Button(Loading(cls=LoadingT.spinner), "Submit Ticket", cls=ButtonT.primary, data_uk_toggle="target: #success-toast; target: #new-ticket")), + cls='space-y-8')), + id="new-ticket") + +@rt +def index(): + tickets = [ + {'id': "TK-1001", 'title': "Cloud Storage Access Error", + 'description': "Unable to access cloud storage with persistent authorization errors. Multiple users affected across marketing department.", + 'status': 'high', 'step': 2, 'department': 'IT Support'}, + {'id': "TK-1002", 'title': "Email Integration Issue", + 'description': "Exchange server not syncing with mobile devices. Affecting external client communications.", + 'status': 'medium', 'step': 1, 'department': 'IT Support'}, + {'id': "TK-1003", 'title': "Office Equipment Setup", + 'description': "New department printer needs configuration and network integration. Required for upcoming client presentation.", + 'status': 'low', 'step': 0, 'department': 'Facilities'} + ] + + return Title("Help Desk Dashboard"), Container( + Section( + DivFullySpaced( + H2("Active Tickets"), + Button(UkIcon("plus-circle", cls="mr-2"), "New Ticket", cls=ButtonT.primary, data_uk_toggle="target: #new-ticket"), + cls='mb-8'), + Grid(*[TicketCard(**ticket) for ticket in tickets], cols=1), + cls="my-6"), + NewTicketModal(), + Toast(DivLAligned(UkIcon('check-circle', cls='mr-2'), "Ticket submitted successfully! Our team will review it shortly."), id="success-toast", alert_cls=AlertT.success, cls=(ToastHT.end, ToastVT.bottom)), + Loading(htmx_indicator=True, type=LoadingT.dots, cls="fixed top-0 right-0 m-4"), + cls="mx-auto max-w-7xl" + ) + +serve()"""FrankenUI Auth Example built with MonsterUI (original design by ShadCN)""" + +from fasthtml.common import * +from monsterui.all import * +from fasthtml.svg import * + +app, rt = fast_app(hdrs=Theme.blue.headers()) + +@rt +def index(): + left = Div(cls="col-span-1 hidden flex-col justify-between bg-zinc-900 p-8 text-white lg:flex")( + Div(cls=(TextT.bold))("Acme Inc"), + Blockquote(cls="space-y-2")( + P(cls=TextT.lg)('"This library has saved me countless hours of work and helped me deliver stunning designs to my clients faster than ever before."'), + Footer(cls=TextT.sm)("Sofia Davis"))) + + right = Div(cls="col-span-2 flex flex-col p-8 lg:col-span-1")( + DivRAligned(Button("Login", cls=ButtonT.ghost)), + DivCentered(cls='flex-1')( + Container( + DivVStacked( + H3("Create an account"), + Small("Enter your email below to create your account", cls=TextT.muted)), + Form( + Input(placeholder="name@example.com"), + Button(Span(cls="mr-2", uk_spinner="ratio: 0.54"), "Sign in with Email", cls=(ButtonT.primary, "w-full"), disabled=True), + DividerSplit(Small("Or continue with"),cls=TextT.muted), + Button(UkIcon('github',cls='mr-2'), "Github", cls=(ButtonT.default, "w-full")), + cls='space-y-6'), + DivVStacked(Small( + "By clicking continue, you agree to our ", + A(cls=AT.muted, href="#demo")("Terms of Service")," and ", + A(cls=AT.muted, href="#demo")("Privacy Policy"),".", + cls=(TextT.muted,"text-center"))), + cls="space-y-6"))) + + return Title("Auth Example"),Grid(left,right,cols=2, gap=0,cls='h-screen') + + +serve()"""FrankenUI Music Example build with MonsterUI (Original design by ShadCN)""" + +from fasthtml.common import * +from monsterui.all import * + +app, rt = fast_app(hdrs=Theme.blue.headers()) + +def MusicLi(t,hk=''): return Li(A(DivFullySpaced(t,P(hk,cls=TextPresets.muted_sm)))) + +music_items = [("About Music", "" ), + ("Preferences", "⌘" ), + ("Hide Music" , "⌘H" ), + ("Hide Others", "⇧⌘H"), + ("Quit Music" , "⌘Q" )] + +file_dd_items = [("New", ""), + ("Open Stream URL", "⌘U"), + ("Close Window", "⌘W"), + ("Library", ""), + ("Import", "⌘O"), + ("Burn Playlist to Disc", ""), + ("Show in Finder", "⇧⌘R"), + ("Convert", ""), + ("Page Setup", "Print")] + +edit_actions = [("Undo", "⌘Z"), + ("Redo", "⇧⌘Z"), + ("Cut", "⌘X"), + ("Copy", "⌘C"), + ("Paste", "⌘V"), + ("Select All", "⌘A"), + ("Deselect All", "⇧⌘A")] + +view_dd_data = ["Show Playing Next", "Show Lyrics", "Show Status Bar", "Hide Sidebar", "Enter Full Screen"] + + +music_headers = NavBar( + Button("Music", cls=ButtonT.ghost+TextT.gray),DropDownNavContainer(Li(A("Music"),NavContainer(map(lambda x: MusicLi(*x), music_items)))), + Button("File", cls=ButtonT.ghost+TextT.gray), DropDownNavContainer(Li(A("File"), NavContainer(map(lambda x: MusicLi(*x), file_dd_items)))), + Button("Edit", cls=ButtonT.ghost+TextT.gray), DropDownNavContainer(Li(A("Edit")),NavContainer( + *map(lambda x: MusicLi(*x), edit_actions), + Li(A(DivFullySpaced("Smart Dictation",UkIcon("mic")))), + Li(A(DivFullySpaced("Emojis & Symbols",UkIcon("globe")))))), + Button("View", cls=ButtonT.ghost+TextT.gray),DropDownNavContainer(Li(A("View"),NavContainer(map(lambda x: MusicLi(x), view_dd_data)))), + ) + + + + +# music_headers = NavBarContainer( +# NavBarLSide( +# NavBarNav( +# Li(A("Music"),NavBarNavContainer(map(lambda x: MusicLi(*x), music_items))), +# Li(A("File"), NavBarNavContainer(map(lambda x: MusicLi(*x), file_dd_items))), +# Li(A("Edit")), +# NavBarNavContainer( +# *map(lambda x: MusicLi(*x), edit_actions), +# Li(A(DivFullySpaced("Smart Dictation",UkIcon("mic")))), +# Li(A(DivFullySpaced("Emojis & Symbols",UkIcon("globe"))))), +# Li(A("View"), +# NavBarNavContainer(map(lambda x: MusicLi(x), view_dd_data))), +# Li(A("Account"), +# NavBarNavContainer( +# NavHeaderLi("Switch Account"), +# *map(MusicLi, ("Andy", "Benoit", "Luis", "Manage Family", "Add Account"))))))) + + +def Album(title,artist): + img_url = 'https://ucarecdn.com/e5607eaf-2b2a-43b9-ada9-330824b6afd7/music1.webp' + return Div( + Div(cls="overflow-hidden rounded-md")(Img(cls="transition-transform duration-200 hover:scale-105", src=img_url)), + Div(cls='space-y-1')(Strong(title),P(artist,cls=TextT.muted))) + +listen_now_albums = (("Roar", "Catty Perry"), ("Feline on a Prayer", "Cat Jovi"),("Fur Elise", "Ludwig van Beethovpurr"),("Purrple Rain", "Prince's Cat")) + +made_for_you_albums = [("Like a Feline", "Catdonna"), + ("Livin' La Vida Purrda", "Ricky Catin"), + ("Meow Meow Rocket", "Elton Cat"), + ("Rolling in the Purr", "Catdelle"), + ("Purrs of Silence", "Cat Garfunkel"), + ("Meow Me Maybe", "Carly Rae Purrsen"),] + +music_content = (Div(H3("Listen Now"), cls="mt-6 space-y-1"), + Subtitle("Top picks for you. Updated daily."), + DividerLine(), + Grid(*[Album(t,a) for t,a in listen_now_albums], cls='gap-8'), + Div(H3("Made for You"), cls="mt-6 space-y-1"), + Subtitle("Your personal playlists. Updated daily."), + DividerLine(), + Grid(*[Album(t,a) for t,a in made_for_you_albums], cols_xl=6)) + +tabs = TabContainer( + Li(A('Music', href='#'), cls='uk-active'), + Li(A('Podcasts', href='#')), + Li(A('Live', cls='opacity-50'), cls='uk-disabled'), + uk_switcher='connect: #component-nav; animation: uk-animation-fade', + alt=True) + +def podcast_tab(): + return Div( + Div(cls='space-y-3 mt-6')( + H3("New Episodes"), + Subtitle("Your favorite podcasts. Updated daily.")), + Div(cls="uk-placeholder flex h-[450px] items-center justify-center rounded-md mt-4",uk_placeholder=True)( + DivVStacked(cls="space-y-6")( + UkIcon("microphone", 3), + H4("No episodes added"), + Subtitle("You have not added any podcasts. Add one below."), + Button("Add Podcast", cls=ButtonT.primary)))) + +discoved_data = [("play-circle","Listen Now"), ("binoculars", "Browse"), ("rss","Radio")] +library_data = [("play-circle", "Playlists"), ("music", "Songs"), ("user", "Made for You"), ("users", "Artists"), ("bookmark", "Albums")] +playlists_data = [("library","Recently Added"), ("library","Recently Played")] + +def MusicSidebarLi(icon, text): return Li(A(DivLAligned(UkIcon(icon), P(text)))) +sidebar = NavContainer( + NavHeaderLi(H3("Discover")), *[MusicSidebarLi(*o) for o in discoved_data], + NavHeaderLi(H3("Library")), *[MusicSidebarLi(*o) for o in library_data], + NavHeaderLi(H3("Playlists")),*[MusicSidebarLi(*o) for o in playlists_data], + cls=(NavT.primary,'space-y-3','pl-8')) + +@rt +def index(): + return Title("Music Example"),Container(music_headers, DividerSplit(), + Grid(sidebar, + Div(cls="col-span-4 border-l border-border")( + Div(cls="px-8 py-6")( + DivFullySpaced( + Div(cls="max-w-80")(tabs), + Button(cls=ButtonT.primary)(DivLAligned(UkIcon('circle-plus')),Div("Add music"))), + Ul(id="component-nav", cls="uk-switcher")( + Li(*music_content), + Li(podcast_tab())))), + cols_sm=1, cols_md=1, cols_lg=5, cols_xl=5)) + +serve()# Buttons & Links API Reference + +See Source + +See Output + +DefaultPrimarySecondaryDangerTextLinkGhost + +[code] + + def ex_buttons(): + return Grid( + Button("Default"), + Button("Primary", cls=ButtonT.primary), + Button("Secondary", cls=ButtonT.secondary), + Button("Danger", cls=ButtonT.destructive), + Button("Text", cls=ButtonT.text), + Button("Link", cls=ButtonT.link), + Button("Ghost", cls=ButtonT.ghost), + ) + +[/code] + +See Source + +See Output + +Default LinkMuted LinkText LinkReset LinkPrimary LinkClassic Link + +[code] + + def ex_links(): + return Div(cls='space-x-4')( + A('Default Link'), + A('Muted Link', cls=AT.muted), + A('Text Link', cls=AT.text), + A('Reset Link', cls=AT.reset), + A('Primary Link', cls=AT.primary), + A('Classic Link', cls=AT.classic),) + +[/code] + +### Button + +Source + +[code] + + Button(*c: Union[str, fastcore.xml.FT], cls: Union[str, enum.Enum] = , submit=True, **kwargs) -> fastcore.xml.FT +[/code] + +> Button with Styling (defaults to `submit` for form submission) + +**Params** + + * `c` Contents of `Button` tag (often text) + + * `cls` Classes in addition to `Button` styling (use `ButtonT` for built in styles) + + * `submit` Whether the button should submit a form + + * `kwargs` + +**Returns:** Button(..., cls='uk-btn') + +* * * + +### ButtonT + +_Options for styling Buttons_ + +Option | Value | Option | Value | Option | Value +---|---|---|---|---|--- +default | uk-btn-default | ghost | uk-btn-ghost | primary | uk-btn-primary +secondary | uk-btn-secondary | destructive | uk-btn-destructive | text | uk-btn-text +link | uk-btn-link | xs | uk-btn-xs | sm | uk-btn-sm +lg | uk-btn-lg | xl | uk-btn-xl | icon | uk-btn-icon + +* * * + +### AT + +_Link styles from https://franken-ui.dev/docs/link_ + +Option | Value | Option | Value +---|---|---|--- +muted | uk-link-muted | text | uk-link-text +reset | uk-link-reset | primary | uk-link text-primary hover:text-primary-focus underline +classic | text-blue-600 hover:text-blue-800 underline | | +# Cards API Reference + +### Example Usage + +See Source + +See Output + +Header + +A card with header and footer + +Input + +Range + +Footer Submit Button + +[code] + + def ex_card(): + return Card( + Form(LabelInput("Input"), + LabelRange("Range")), + header=Div( + CardTitle("Header"), + P("A card with header and footer",cls=TextPresets.muted_sm)), + footer=DivLAligned(Button("Footer Submit Button"))) + +[/code] + +See Source + +See Output + +#### Creating Custom FastHTML Tags for Markdown Rendering + +A step by step tutorial to rendering markdown in FastHTML using zero-md inside of DaisyUI chat bubbles + +Isaac Flath20-October-2024 + +FastHTMLHTMXWeb Apps + +Read + +[code] + + def ex_card2_wide(): + def Tags(cats): return DivLAligned(map(Label, cats)) + + return Card( + DivLAligned( + A(Img(src="https://picsum.photos/200/200?random=12", style="width:200px"),href="#"), + Div(cls='space-y-3 uk-width-expand')( + H4("Creating Custom FastHTML Tags for Markdown Rendering"), + P("A step by step tutorial to rendering markdown in FastHTML using zero-md inside of DaisyUI chat bubbles"), + DivFullySpaced(map(Small, ["Isaac Flath", "20-October-2024"]), cls=TextT.muted), + DivFullySpaced( + Tags(["FastHTML", "HTMX", "Web Apps"]), + Button("Read", cls=(ButtonT.primary,'h-6'))))), + cls=CardT.hover) + +[/code] + +See Source + +See Output + +#### Creating Custom FastHTML Tags for Markdown Rendering + +A step by step tutorial to rendering markdown in FastHTML using zero-md inside of DaisyUI chat bubbles + +Isaac Flath20-October-2024 + +FastHTMLHTMXWeb Apps + +Read + +[code] + + def ex_card2_tall(): + def Tags(cats): return DivLAligned(map(Label, cats)) + + return Card( + Div( + A(Img(src="https://picsum.photos/400/200?random=14"), href="#"), + Div(cls='space-y-3 uk-width-expand')( + H4("Creating Custom FastHTML Tags for Markdown Rendering"), + P("A step by step tutorial to rendering markdown in FastHTML using zero-md inside of DaisyUI chat bubbles"), + DivFullySpaced(map(Small, ["Isaac Flath", "20-October-2024"]), cls=TextT.muted), + DivFullySpaced( + Tags(["FastHTML", "HTMX", "Web Apps"]), + Button("Read", cls=(ButtonT.primary,'h-6'))))), + cls=CardT.hover) + +[/code] + +See Source + +See Output + +### Sarah Chen + +Engineering Lead + +San Francisco + +### James Wilson + +Senior Developer + +New York + +### Maria Garcia + +UX Designer + +London + +### Alex Kumar + +Product Manager + +Singapore + +### Emma Brown + +DevOps Engineer + +Toronto + +### Marcus Johnson + +Frontend Developer + +Berlin + +[code] + + def ex_card3(): + def team_member(name, role, location="Remote"): + return Card( + DivLAligned( + DiceBearAvatar(name, h=24, w=24), + Div(H3(name), P(role))), + footer=DivFullySpaced( + DivHStacked(UkIcon("map-pin", height=16), P(location)), + DivHStacked(*(UkIconLink(icon, height=16) for icon in ("mail", "linkedin", "github"))))) + team = [ + team_member("Sarah Chen", "Engineering Lead", "San Francisco"), + team_member("James Wilson", "Senior Developer", "New York"), + team_member("Maria Garcia", "UX Designer", "London"), + team_member("Alex Kumar", "Product Manager", "Singapore"), + team_member("Emma Brown", "DevOps Engineer", "Toronto"), + team_member("Marcus Johnson", "Frontend Developer", "Berlin") + ] + return Grid(*team, cols_sm=1, cols_md=1, cols_lg=2, cols_xl=3) + +[/code] + +### API Reference + +### Card + +Source + +[code] + + Card(*c, header: Union[fastcore.xml.FT, Iterable[fastcore.xml.FT]] = None, footer: Union[fastcore.xml.FT, Iterable[fastcore.xml.FT]] = None, body_cls='space-y-6', header_cls=(), footer_cls=(), cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a Card with a header, body, and footer + +**Params** + + * `c` Components that go in the body (Main content of the card such as a form, and image, a signin form, etc.) + + * `header` Component(s) that goes in the header (often a `ModalTitle` and a subtitle) + + * `footer` Component(s) that goes in the footer (often a `ModalCloseButton`) + + * `body_cls` classes for the body + + * `header_cls` classes for the header + + * `footer_cls` classes for the footer + + * `cls` class for outermost component + + * `kwargs` + +**Returns:** Card component + +### CardTitle + +Source + +[code] + + CardTitle(*c, cls=(), **kwargs) +[/code] + +> Creates a card title + +**Params** + + * `c` Components (often a string) + + * `cls` Additional classes on the div + + * `kwargs` + +* * * + +### CardT + +_Card styles from UIkit_ + +Option | Value | Option | Value +---|---|---|--- +default | uk-card-default | primary | uk-card-primary +secondary | uk-card-secondary | destructive | uk-card-destructive +hover | uk-card hover:shadow-lg hover:-translate-y-1 transition-all duration-200 | | + +The remainder of these are only needed if you're doing something really special. They are used in the `Card` function to generate the boilerplate for you. + +### CardContainer + +Source + +[code] + + CardContainer(*c, cls=, **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a card container + +**Params** + + * `c` Components (typically `CardHeader`, `CardBody`, `CardFooter`) + + * `cls` Additional classes on the div + + * `kwargs` + +**Returns:** Container for a card + +### CardHeader + +Source + +[code] + + CardHeader(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a card header + +**Params** + + * `c` Components that goes in the header (often a `ModalTitle` and description) + + * `cls` Additional classes on the div + + * `kwargs` + +**Returns:** Container for the header of a card + +### CardBody + +Source + +[code] + + CardBody(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a card body + +**Params** + + * `c` Components that go in the body (Main content of the card such as a form, and image, a signin form, etc.) + + * `cls` Additional classes on the div + + * `kwargs` + +**Returns:** Container for the body of a card + +### CardFooter + +Source + +[code] + + CardFooter(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a card footer + +**Params** + + * `c` Components that go in the footer (often a `ModalCloseButton`) + + * `cls` Additional classes on the div + + * `kwargs` + +**Returns:** Container for the footer of a card +# Articles, Containers & Sections API Reference + +### ArticleMeta + +Source + +[code] + + ArticleMeta(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> A metadata component for use within an Article showing things like date, author etc + +**Params** + + * `c` contents of ArticleMeta tag (often other tags) + + * `cls` Classes in addition to ArticleMeta styling + + * `kwargs` + +**Returns:** P(..., cls='uk-article-meta') + +### ArticleTitle + +Source + +[code] + + ArticleTitle(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> A title component for use within an Article + +**Params** + + * `c` contents of ArticleTitle tag (often other tags) + + * `cls` Classes in addition to ArticleTitle styling + + * `kwargs` + +**Returns:** H1(..., cls='uk-article-title') + +### Article + +Source + +[code] + + Article(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> A styled article container for blog posts or similar content + +**Params** + + * `c` contents of Article tag (often other tags) + + * `cls` Classes in addition to Article styling + + * `kwargs` + +**Returns:** Article(..., cls='uk-article') + +See Source + +See Output + +# Sample Article Title + +By: John Doe + +lorem ipsum dolor sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + +[code] + + def ex_articles(): + return Article( + ArticleTitle("Sample Article Title"), + Subtitle("By: John Doe"), + P('lorem ipsum dolor sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.')) + +[/code] + +### Container + +Source + +[code] + + Container(*c, cls=('mt-5', ), **kwargs) -> fastcore.xml.FT +[/code] + +> Div to be used as a container that often wraps large sections or a page of content + +**Params** + + * `c` Contents of Container tag (often other FT Components) + + * `cls` Classes in addition to Container styling + + * `kwargs` + +**Returns:** Container(..., cls='uk-container') + +* * * + +### ContainerT + +_Max width container sizes from https://franken-ui.dev/docs/container_ + +Option | Value | Option | Value +---|---|---|--- +xs | uk-container-xs | sm | uk-container-sm +lg | uk-container-lg | xl | uk-container-xl +expand | uk-container-expand | | + +See Source + +See Output + +This is a sample container with custom styling. + +[code] + + def ex_containers(): + return Container( + "This is a sample container with custom styling.", + cls=ContainerT.xs, + style="background-color: #FFA500; color: #000000") + +[/code] + +### Section + +Source + +[code] + + Section(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Section with styling and margins + +**Params** + + * `c` contents of Section tag (often other tags) + + * `cls` Classes in addition to Section styling + + * `kwargs` + +**Returns:** Div(..., cls='uk-section') + +* * * + +### SectionT + +_Section styles from https://franken-ui.dev/docs/section_ + +Option | Value | Option | Value | Option | Value +---|---|---|---|---|--- +default | uk-section-default | muted | uk-section-muted | primary | uk-section-primary +secondary | uk-section-secondary | xs | uk-section-xsmall | sm | uk-section-small +lg | uk-section-large | xl | uk-section-xlarge | remove_vertical | uk-section-remove-vertical +# Dividers API Reference + +### Divider + +Source + +[code] + + Divider(*c, cls=('my-4', ), **kwargs) -> fastcore.xml.FT +[/code] + +> Divider with default styling and margin + +**Params** + + * `c` contents of Divider tag (often nothing) + + * `cls` Classes in addition to Divider styling + + * `kwargs` + +**Returns:** Hr(..., cls='uk-divider-icon') or Div(..., cls='uk-divider-vertical') + +* * * + +### DividerT + +_Divider Styles from https://franken-ui.dev/docs/divider_ + +Option | Value | Option | Value +---|---|---|--- +icon | uk-divider-icon | sm | uk-divider-sm +vertical | uk-divider-vertical | | + +See Source + +See Output + +Small Divider + +* * * + +Vertical Divider + +Icon Divider + +* * * +[code] + + def ex_dividers(): + return Div( + P("Small Divider"), + Divider(cls=DividerT.sm), + DivCentered( + P("Vertical Divider"), + Divider(cls=DividerT.vertical)), + DivCentered("Icon Divider"), + Divider(cls=DividerT.icon)) + +[/code] + +### DividerSplit + +Source + +[code] + + DividerSplit(*c, cls=(), line_cls=(), text_cls=()) +[/code] + +> Creates a simple horizontal line divider with configurable thickness and vertical spacing + +**Params** + + * `c` + + * `cls` + + * `line_cls` + + * `text_cls` + +See Source + +See Output + +Or continue with + +[code] + + def ex_dividersplit(): + return DividerSplit(P("Or continue with", cls=TextPresets.muted_sm)) + +[/code] + +### DividerLine + +Source + +[code] + + DividerLine(lwidth=2, y_space=4) +[/code] + +> **Params** + + * `lwidth` + + * `y_space` + +See Source + +See Output + +* * * +[code] + + def ex_dividerline(): + return DividerLine() + +[/code] +# Forms and User Inputs API Reference + +### Example Form + +This form was live coded in a 5 minute video here + +See Source + +See Output + +### Emergency Contact Form + +Please fill out the form completely + +First Name + +Last Name + +Email + +Phone + +### Relationship to patient + +Parent + +Sibling + +Friend + +Spouse + +Significant Other + +Relative + +Child + +Other + +Address + +Address Line 2 + +City + +State + +Zip + +Submit Form + +[code] + + def ex_form(): + relationship = ["Parent",'Sibling', "Friend", "Spouse", "Significant Other", "Relative", "Child", "Other"] + return Div(cls='space-y-4')( + DivCentered( + H3("Emergency Contact Form"), + P("Please fill out the form completely", cls=TextPresets.muted_sm)), + Form(cls='space-y-4')( + Grid(LabelInput("First Name",id='fn'), LabelInput("Last Name",id='ln')), + Grid(LabelInput("Email", id='em'), LabelInput("Phone", id='ph')), + H3("Relationship to patient"), + Grid(*[LabelCheckboxX(o) for o in relationship], cols=4, cls='space-y-3'), + LabelInput("Address", id='ad'), + LabelInput("Address Line 2", id='ad2'), + Grid(LabelInput("City", id='ct'), LabelInput("State", id='st')), + LabelInput("Zip", id='zp'), + DivCentered(Button("Submit Form", cls=ButtonT.primary)))) + +[/code] + +See Source + +See Output + +Upload Button! + +Upload Zone + +[code] + + def ex_upload(): + return Div(Upload("Upload Button!", id='upload1'), + UploadZone(DivCentered(Span("Upload Zone"), UkIcon("upload")), id='upload2'), + cls='space-y-4') + +[/code] + +### FormLabel + +Source + +[code] + + FormLabel(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> A Label with default styling + +**Params** + + * `c` contents of FormLabel tag (often text) + + * `cls` Classes in addition to FormLabel styling + + * `kwargs` + +**Returns:** Label(..., cls='uk-form-label') + +See Source + +See Output + +Form Label + +[code] + + def ex_formlabel(): + return FormLabel("Form Label") + +[/code] + +### Input + +Source + +[code] + + Input(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> An Input with default styling + +**Params** + + * `c` contents of Input tag (often nothing) + + * `cls` Classes in addition to Input styling + + * `kwargs` + +**Returns:** Input(..., cls='uk-input') + +See Source + +See Output + +Input + +[code] + + def ex_input(): + return Div( + Input(placeholder="Enter text"), + LabelInput(label="Input", id='myid')) + +[/code] + +### LabelInput + +Source + +[code] + + LabelInput(label: str | fastcore.xml.FT, lbl_cls='', input_cls='', cls='space-y-2', id='', **kwargs) -> fastcore.xml.FT +[/code] + +> A `FormLabel` and `Input` pair that provides default spacing and links/names them based on id + +**Params** + + * `label` FormLabel content (often text) + + * `lbl_cls` Additional classes for `FormLabel` + + * `input_cls` Additional classes for `Input` + + * `cls` Classes on container (default is `'space-y-2'` to prevent scrunched up form elements) + + * `id` id for `FormLabel` and `Input` (`id`, `name` and `for` attributes are set to this value) + + * `kwargs` + +**Returns:** Div(cls='space-y-2')(`FormLabel`, `Input`) + +### LabelCheckboxX + +Source + +[code] + + LabelCheckboxX(label: str | fastcore.xml.FT, lbl_cls='', input_cls='', container=functools.partial(, 'div', void_=False), cls='flex items-center space-x-2', id='', **kwargs) -> fastcore.xml.FT +[/code] + +> A FormLabel and CheckboxX pair that provides default spacing and links/names them based on id + +**Params** + + * `label` FormLabel content (often text) + + * `lbl_cls` Additional classes for `FormLabel` + + * `input_cls` Additional classes for `CheckboxX` + + * `container` Container to wrap label and input in (default is Div) + + * `cls` Classes on container (default is 'flex items-center space-x-2') + + * `id` id for `FormLabel` and `CheckboxX` (`id`, `name` and `for` attributes are set to this value) + + * `kwargs` + +**Returns:** Div(cls='flex items-center space-x-2')(`FormLabel`, `CheckboxX`) + +### LabelSwitch + +Source + +[code] + + LabelSwitch(label: str | fastcore.xml.FT, lbl_cls='', input_cls='', cls='space-x-2', id='', *, container=functools.partial(, 'div', void_=False)) -> fastcore.xml.FT +[/code] + +> **Params** + + * `label` FormLabel content (often text) + + * `lbl_cls` Additional classes for `FormLabel` + + * `input_cls` Additional classes for `Switch` + + * `container` Container to wrap label and input in (default is Div) + + * `cls` Classes on container (default is `'space-x-2'` to prevent scrunched up form elements) + + * `id` id for `FormLabel` and `Switch` (`id`, `name` and `for` attributes are set to this value) + +**Returns:** Div(cls='space-y-2')(`FormLabel`, `Switch`) + +### LabelRange + +Source + +[code] + + LabelRange(label: str | fastcore.xml.FT, lbl_cls='', input_cls='', cls='space-y-6', id='', value='', min=None, max=None, step=None, label_range=True, *, container=functools.partial(, 'div', void_=False)) -> fastcore.xml.FT +[/code] + +> A FormLabel and Range pair that provides default spacing and links/names them based on id + +**Params** + + * `label` FormLabel content (often text) + + * `lbl_cls` Additional classes for `FormLabel` + + * `input_cls` Additional classes for `Range` + + * `container` Container to wrap label and input in (default is Div) + + * `cls` Classes on container (default is `'space-y-2'` to prevent scrunched up form elements) + + * `id` id for `FormLabel` and `Range` (`id`, `name` and `for` attributes are set to this value) + + * `value` Value for the range input + + * `min` Minimum value + + * `max` Maximum value + + * `step` Step size + + * `label_range` Whether to show the range value label (label for the `Range` component) + +**Returns:** Div(cls='space-y-2')(`FormLabel`, `Range`) + +### LabelTextArea + +Source + +[code] + + LabelTextArea(label: str | fastcore.xml.FT, value='', lbl_cls='', input_cls='', cls='space-y-2', id='', **kwargs) -> fastcore.xml.FT +[/code] + +> **Params** + + * `label` FormLabel content (often text) + + * `value` Value for the textarea + + * `lbl_cls` Additional classes for `FormLabel` + + * `input_cls` Additional classes for `TextArea` + + * `cls` Classes on container (default is `'space-y-2'` to prevent scrunched up form elements) + + * `id` id for `FormLabel` and `TextArea` (`id`, `name` and `for` attributes are set to this value) + + * `kwargs` + +**Returns:** Div(cls='space-y-2')(`FormLabel`, `TextArea`) + +### LabelRadio + +Source + +[code] + + LabelRadio(label: str | fastcore.xml.FT, lbl_cls='', input_cls='', container=functools.partial(, 'div', void_=False), cls='flex items-center space-x-2', id='', **kwargs) -> fastcore.xml.FT +[/code] + +> A FormLabel and Radio pair that provides default spacing and links/names them based on id + +**Params** + + * `label` FormLabel content (often text) + + * `lbl_cls` Additional classes for `FormLabel` + + * `input_cls` Additional classes for `Radio` + + * `container` Container to wrap label and input in (default is Div) + + * `cls` Classes on container (default is 'flex items-center space-x-2') + + * `id` id for `FormLabel` and `Radio` (`id`, `name` and `for` attributes are set to this value) + + * `kwargs` + +**Returns:** Div(cls='flex items-center space-x-2')(`FormLabel`, `Radio`) + +### LabelSelect + +Source + +[code] + + LabelSelect(*option, label: str | fastcore.xml.FT, lbl_cls='', input_cls='', container=functools.partial(, 'div', void_=False), cls='space-y-2', id='', **kwargs) +[/code] + +> A FormLabel and Select pair that provides default spacing and links/names them based on id (usually UkLabelSelect is a better choice) + +**Params** + + * `option` Options for the select dropdown (can use `Options` helper function to create) + + * `label` FormLabel content (often text) + + * `lbl_cls` Additional classes for `FormLabel` + + * `input_cls` Additional classes for `Select` + + * `container` Container to wrap label and input in (default is Div) + + * `cls` Classes on container (default is 'space-y-2') + + * `id` id for `FormLabel` and `Select` (`id`, `name` and `for` attributes are set to this value) + + * `kwargs` + +### Progress + +Source + +[code] + + Progress(*c, cls=(), value='', max='100', **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a progress bar + +**Params** + + * `c` Components to put in the progress bar (often nothing) + + * `cls` Additional classes on the progress bar + + * `value` Value of the progress bar + + * `max` Max value of the progress bar (defaults to 100 for percentage) + + * `kwargs` + +**Returns:** Progress(..., cls='uk-progress') + +See Source + +See Output + +[code] + + def ex_progress(): + return Progress(value=20, max=100) + +[/code] + +### Radio + +Source + +[code] + + Radio(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> A Radio with default styling + +**Params** + + * `c` contents of Radio tag (often nothing) + + * `cls` Classes in addition to Radio styling + + * `kwargs` + +**Returns:** Input(..., cls='uk-radio', type='radio') + +See Source + +See Output + +Radio + +[code] + + def ex_radio(): + return Div( + Radio(name="radio-group", id="radio1"), + LabelRadio(label="Radio", id='radio1',cls='flex items-center space-x-4')) + +[/code] + +### CheckboxX + +Source + +[code] + + CheckboxX(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> A Checkbox with default styling + +**Params** + + * `c` contents of CheckboxX tag (often nothing) + + * `cls` Classes in addition to CheckboxX styling + + * `kwargs` + +**Returns:** Input(..., cls='uk-checkbox', type='checkbox') + +See Source + +See Output + +Checkbox + +[code] + + def ex_checkbox(): + return Div( + CheckboxX(), + LabelCheckboxX(label="Checkbox", id='checkbox1')) + +[/code] + +### Range + +Source + +[code] + + Range(*c, value='', label=True, min=None, max=None, step=None, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> A Range with default styling + +**Params** + + * `c` contents of Range tag (often nothing) + + * `value` + + * `label` + + * `min` + + * `max` + + * `step` + + * `cls` Classes in addition to Range styling + + * `kwargs` + +**Returns:** Input(..., cls='uk-range', type='range') + +See Source + +See Output + +Basic Range + +Range with Label + +Multiple Values + +Custom Range + +[code] + + def ex_range(): + return Div( + Range(), + Range(label='kg', value="25,75", min=20, max=75), + LabelRange('Basic Range', value='50', min=0, max=100, step=1), + LabelRange('Range with Label', value='75', min=0, max=100, step=5, label_range=True), + LabelRange('Multiple Values', value='25,75', min=0, max=100, step=5, label_range=True), + LabelRange('Custom Range', value='500', min=0, max=1000, step=100, label_range=True) + ) + +[/code] + +### Switch + +Source + +[code] + + Switch(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> A Switch with default styling + +**Params** + + * `c` contents of Switch tag (often nothing) + + * `cls` Classes in addition to Switch styling + + * `kwargs` + +**Returns:** Input(..., cls='uk-toggle-switch uk-toggle-switch-primary min-w-9', type='checkbox') + +See Source + +See Output + +Switch + +[code] + + def ex_switch(): + return Div( + Switch(id="switch"), + LabelSwitch(label="Switch", id='switch')) + +[/code] + +### TextArea + +Source + +[code] + + TextArea(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> A Textarea with default styling + +**Params** + + * `c` contents of TextArea tag (often text) + + * `cls` Classes in addition to TextArea styling + + * `kwargs` + +**Returns:** TextArea(..., cls='uk-textarea') + +See Source + +See Output + +TextArea + +[code] + + def ex_textarea(): + return Div( + TextArea(placeholder="Enter multiple lines of text"), + LabelTextArea(label="TextArea", id='myid')) + +[/code] + +### Select + +Source + +[code] + + Select(*option, inp_cls=(), cls=('h-10',), cls_custom='button: uk-input-fake dropdown: w-full', id='', name='', placeholder='', searchable=False, insertable=False, select_kwargs=None, **kwargs) +[/code] + +> Creates a select dropdown with uk styling and option for adding a search box + +**Params** + + * `option` Options for the select dropdown (can use `Options` helper function to create) + + * `inp_cls` Additional classes for the select input + + * `cls` Classes for the outer div (default h-10 for consistent height) + + * `cls_custom` Classes for the Uk_Select web component + + * `id` ID for the select input + + * `name` Name attribute for the select input + + * `placeholder` Placeholder text for the select input + + * `searchable` Whether the select should be searchable + + * `insertable` Whether to allow user-defined options to be added + + * `select_kwargs` Additional Arguments passed to Select + + * `kwargs` + +See Source + +See Output + +Option 1Option 2Option 3 + +Select + +Option 1Option 2Option 3 + +[code] + + def ex_select(): + return Div( + Select(map(Option, ["Option 1", "Option 2", "Option 3"])), + LabelSelect(map(Option, ["Option 1", "Option 2", "Option 3"]), label="Select", id='myid')) + +[/code] + +### Example: Insertable Select + +In a production app, the user-inserted option would be saved server-side (db, session etc.) + +See Source + +See Output + +AppleOrangeBananaMango + +AppleBananaMangoOrange + +[code] + + def ex_insertable_select1(): + fruit_opts = ['apple', 'orange', 'banana', 'mango'] + + return Grid( + Select(Option('Apple', value='apple'), + Option('Orange', value='orange'), + Option('Banana', value='banana'), + Option('Mango', value='mango'), + id="fruit", icon=True, insertable=True, placeholder="Choose a fruit..."), + + Select(Optgroup(label="Fruit")( + *map(lambda l: Option(l.capitalize(), value=l), sorted(fruit_opts))), + id="fruit", icon=True, insertable=True, placeholder="Choose a fruit...", + cls_custom="button: uk-input-fake justify-between w-full; dropdown: w-full")) + +[/code] + +### Legend + +Source + +[code] + + Legend(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> A Legend with default styling + +**Params** + + * `c` contents of Legend tag (often other tags) + + * `cls` Classes in addition to Legend styling + + * `kwargs` + +**Returns:** Legend(..., cls='uk-legend') + +### Fieldset + +Source + +[code] + + Fieldset(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> A Fieldset with default styling + +**Params** + + * `c` contents of Fieldset tag (often other tags) + + * `cls` Classes in addition to Fieldset styling + + * `kwargs` + +**Returns:** Fieldset(..., cls='uk-fieldset') +# HTML Styling API Reference + +See Source + +See Output + +

Hello, World!

This is a paragraph

+ +[code] + + def ex_applyclasses(): + return apply_classes('

Hello, World!

This is a paragraph

') + +[/code] +
# Icons & Images API Reference + +# Avatars + +See Source + +See Output + +[code] + + def ex_dicebear(): + return DivLAligned( + DiceBearAvatar('Isaac Flath',10,10), + DiceBearAvatar('Aaliyah',10,10), + DiceBearAvatar('Alyssa',10,10)) + +[/code] + +### DiceBearAvatar + +Source + +[code] + + DiceBearAvatar(seed_name: str, h: int = 20, w: int = 20) +[/code] + +> Creates an Avatar using https://dicebear.com/ + +**Params** + + * `seed_name` Seed name (ie 'Isaac Flath') + + * `h` Height + + * `w` Width + +# PlaceHolder Images + +See Source + +See Output + +[code] + + def ex_picsum(): + return Grid(PicSumImg(100,100), PicSumImg(100,100, blur=6),PicSumImg(100,100, grayscale=True)) + +[/code] + +### PicSumImg + +Source + +[code] + + PicSumImg(h: int = 200, w: int = 200, id: int = None, grayscale: bool = False, blur: int = None, **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a placeholder image using https://picsum.photos/ + +**Params** + + * `h` Height in pixels + + * `w` Width in pixels + + * `id` Optional specific image ID to use + + * `grayscale` Whether to return grayscale version + + * `blur` Optional blur amount (1-10) + + * `kwargs` + +**Returns:** Img tag with picsum image + +# Icons + +Icons use Lucide icons - you can find a full list of icons in their docs. + +See Source + +See Output + +[code] + + def ex_icon(): + return Grid( + UkIcon('chevrons-right', height=15, width=15), + UkIcon('bug', height=15, width=15), + UkIcon('phone-call', height=15, width=15), + UkIcon('maximize-2', height=15, width=15), + UkIcon('thumbs-up', height=15, width=15),) + +[/code] + +### UkIcon + +Source + +[code] + + UkIcon(icon: str, height: int = None, width: int = None, stroke_width: int = None, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates an icon using lucide icons + +**Params** + + * `icon` Icon name from lucide icons + + * `height` + + * `width` + + * `stroke_width` Thickness of lines + + * `cls` Additional classes on the `Uk_icon` tag + + * `kwargs` + +**Returns:** a lucide icon of the specified size + +See Source + +See Output + +[code] + + def ex_iconlink(): + return DivLAligned( + UkIconLink('chevrons-right'), + UkIconLink('chevrons-right', button=True, cls=ButtonT.primary)) + +[/code] + +### UkIconLink + +Source + +[code] + + UkIconLink(icon: str, height: int = None, width: int = None, stroke_width: int = None, cls=(), button: bool = False, **kwargs) -> fastcore.xml.FT +[/code] + +> Creates an icon link using lucide icons + +**Params** + + * `icon` Icon name from lucide icons + + * `height` + + * `width` + + * `stroke_width` Thickness of lines + + * `cls` Additional classes on the icon + + * `button` Whether to use a button (defaults to a link) + + * `kwargs` + +**Returns:** a lucide icon button or link of the specified size +# Layout (Flex and Grid) API Reference + +This page covers `Grid`s, which are often used for general structure, `Flex` which is often used for layout of components that are not grid based, padding and positioning that can help you make your layout look good, and dividers that can help break up the page + +## Grid + +See Source + +See Output + +Column 1 Item 1 + +Column 1 Item 2 + +Column 1 Item 3 + +Column 2 Item 1 + +Column 2 Item 2 + +Column 2 Item 3 + +Column 3 Item 1 + +Column 3 Item 2 + +Column 3 Item 3 + +[code] + + def ex_grid(): + return Grid( + Div( + P("Column 1 Item 1"), + P("Column 1 Item 2"), + P("Column 1 Item 3")), + Div( + P("Column 2 Item 1"), + P("Column 2 Item 2"), + P("Column 2 Item 3")), + Div( + P("Column 3 Item 1"), + P("Column 3 Item 2"), + P("Column 3 Item 3"))) + +[/code] + +### Grid + +Source + +[code] + + Grid(*div, cols_min: int = 1, cols_max: int = 4, cols_sm: int = None, cols_md: int = None, cols_lg: int = None, cols_xl: int = None, cols: int = None, cls='gap-4', **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a responsive grid layout with smart defaults based on content + +**Params** + + * `div` `Div` components to put in the grid + + * `cols_min` Minimum number of columns at any screen size + + * `cols_max` Maximum number of columns allowed at any screen size + + * `cols_sm` Number of columns on small screens + + * `cols_md` Number of columns on medium screens + + * `cols_lg` Number of columns on large screens + + * `cols_xl` Number of columns on extra large screens + + * `cols` Number of columns on all screens + + * `cls` Additional classes on the grid (tip: `gap` provides spacing for grids) + + * `kwargs` + +**Returns:** Responsive grid component + +#### Practical Grid Example + +See Source + +See Output + +#### Laptop + +$999 + +Add to Cart + +#### Smartphone + +$599 + +Add to Cart + +#### Headphones + +$199 + +Add to Cart + +#### Smartwatch + +$299 + +Add to Cart + +#### Tablet + +$449 + +Add to Cart + +#### Camera + +$799 + +Add to Cart + +[code] + + def ex_product_grid(): + products = [ + {"name": "Laptop", "price": "$999", "img": "https://picsum.photos/200/100?random=1"}, + {"name": "Smartphone", "price": "$599", "img": "https://picsum.photos/200/100?random=2"}, + {"name": "Headphones", "price": "$199", "img": "https://picsum.photos/200/100?random=3"}, + {"name": "Smartwatch", "price": "$299", "img": "https://picsum.photos/200/100?random=4"}, + {"name": "Tablet", "price": "$449", "img": "https://picsum.photos/200/100?random=5"}, + {"name": "Camera", "price": "$799", "img": "https://picsum.photos/200/100?random=6"}, + ] + + product_cards = [ + Card( + Img(src=p["img"], alt=p["name"], style="width:100%; height:100px; object-fit:cover;"), + H4(p["name"], cls="mt-2"), + P(p["price"], cls=TextPresets.bold_sm), + Button("Add to Cart", cls=(ButtonT.primary, "mt-2")) + ) for p in products + ] + + return Grid(*product_cards, cols_lg=3) + +[/code] + +## Flex + +Play Flex Box Froggy to get an understanding of flex box. + +### DivFullySpaced + +Source + +[code] + + DivFullySpaced(*c, cls='w-full', **kwargs) +[/code] + +> Creates a flex div with it's components having as much space between them as possible + +**Params** + + * `c` Components + + * `cls` Classes for outer div (`w-full` makes it use all available width) + + * `kwargs` + +See Source + +See Output + +LeftCenterRight + +[code] + + def ex_fully_spaced_div(): + return DivFullySpaced( + Button("Left", cls=ButtonT.primary), + Button("Center", cls=ButtonT.secondary), + Button("Right", cls=ButtonT.destructive) + ) + +[/code] + +### DivCentered + +Source + +[code] + + DivCentered(*c, cls='space-y-4', vstack=True, **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a flex div with it's components centered in it + +**Params** + + * `c` Components + + * `cls` Classes for outer div (`space-y-4` provides spacing between components) + + * `vstack` Whether to stack the components vertically + + * `kwargs` + +**Returns:** Div with components centered in it + +See Source + +See Output + +### Centered Title + +This content is centered both horizontally and vertically. + +[code] + + def ex_centered_div(): + return DivCentered( + H3("Centered Title"), + P("This content is centered both horizontally and vertically.") + ) + +[/code] + +### DivLAligned + +Source + +[code] + + DivLAligned(*c, cls='space-x-4', **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a flex div with it's components aligned to the left + +**Params** + + * `c` Components + + * `cls` Classes for outer div + + * `kwargs` + +**Returns:** Div with components aligned to the left + +See Source + +See Output + +#### Left Aligned Title + +Some text that's left-aligned with the title and image. + +[code] + + def ex_l_aligned_div(): + return DivLAligned( + Img(src="https://picsum.photos/100/100?random=1", style="max-width: 100px;"), + H4("Left Aligned Title"), + P("Some text that's left-aligned with the title and image.") + ) + +[/code] + +### DivRAligned + +Source + +[code] + + DivRAligned(*c, cls='space-x-4', **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a flex div with it's components aligned to the right + +**Params** + + * `c` Components + + * `cls` Classes for outer div + + * `kwargs` + +**Returns:** Div with components aligned to the right + +See Source + +See Output + +Action + +Right-aligned text + +[code] + + def ex_r_aligned_div(): + return DivRAligned( + Button("Action", cls=ButtonT.primary), + P("Right-aligned text"), + Img(src="https://picsum.photos/100/100?random=3", style="max-width: 100px;") + ) + +[/code] + +### DivVStacked + +Source + +[code] + + DivVStacked(*c, cls='space-y-4', **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a flex div with it's components stacked vertically + +**Params** + + * `c` Components + + * `cls` Additional classes on the div (tip: `space-y-4` provides spacing between components) + + * `kwargs` + +**Returns:** Div with components stacked vertically + +See Source + +See Output + +## Vertical Stack + +First paragraph in the stack + +Second paragraph in the stack + +Action Button + +[code] + + def ex_v_stacked_div(): + return DivVStacked( + H2("Vertical Stack"), + P("First paragraph in the stack"), + P("Second paragraph in the stack"), + Button("Action Button", cls=ButtonT.secondary) + ) + +[/code] + +### DivHStacked + +Source + +[code] + + DivHStacked(*c, cls='space-x-4', **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a flex div with it's components stacked horizontally + +**Params** + + * `c` Components + + * `cls` Additional classes on the div (`space-x-4` provides spacing between components) + + * `kwargs` + +**Returns:** Div with components stacked horizontally + +See Source + +See Output + +#### Column 1 + +Content for column 1 + +#### Column 2 + +Content for column 2 + +#### Column 3 + +Content for column 3 + +[code] + + def ex_h_stacked_div(): + return DivHStacked( + Div(H4("Column 1"), P("Content for column 1")), + Div(H4("Column 2"), P("Content for column 2")), + Div(H4("Column 3"), P("Content for column 3")) + ) + +[/code] + +* * * + +### FlexT + +_Flexbox modifiers using Tailwind CSS_ + +Option | Value | Option | Value | Option | Value | Option | Value +---|---|---|---|---|---|---|--- +block | flex | inline | inline-flex | left | justify-start | center | justify-center +right | justify-end | between | justify-between | around | justify-around | stretch | items-stretch +top | items-start | middle | items-center | bottom | items-end | row | flex-row +row_reverse | flex-row-reverse | column | flex-col | column_reverse | flex-col-reverse | nowrap | flex-nowrap +wrap | flex-wrap | wrap_reverse | flex-wrap-reverse | | | | +# Lightbox API Reference + +See Source + +See Output + +Open + +[code] + + def ex_lightbox1(): + return LightboxContainer( + LightboxItem(Button("Open"), href='https://picsum.photos/id/100/1280/720.webp', data_alt='A placeholder image to demonstrate the lightbox', data_caption='This is my super cool caption'), + ) + +[/code] + +See Source + +See Output + +Open + +[code] + + def ex_lightbox2(): + return LightboxContainer( + LightboxItem(Button("Open"), href='https://picsum.photos/id/100/1280/720.webp', data_alt='A placeholder image to demonstrate the lightbox', data_caption='Image 1'), + LightboxItem(href='https://picsum.photos/id/101/1280/720.webp', data_alt='A placeholder image to demonstrate the lightbox', data_caption='Image 2'), + LightboxItem(href='https://picsum.photos/id/102/1280/720.webp', data_alt='A placeholder image to demonstrate the lightbox', data_caption='Image 3'), + ) + +[/code] + +See Source + +See Output + +mp4YoutubeVimeoIframe + +[code] + + def ex_lightbox3(): + return LightboxContainer( + LightboxItem(Button("mp4"), href='https://yootheme.com/site/images/media/yootheme-pro.mp4'), + LightboxItem(Button("Youtube"), href='https://www.youtube.com/watch?v=c2pz2mlSfXA'), + LightboxItem(Button("Vimeo"), href='https://vimeo.com/1084537'), + LightboxItem(Button("Iframe"), data_type='iframe', href='https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d4740.819266853735!2d9.99008871708242!3d53.550454675412404!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0%3A0x3f9d24afe84a0263!2sRathaus!5e0!3m2!1sde!2sde!4v1499675200938')) + +[/code] + +### LightboxContainer + +Source + +[code] + + LightboxContainer(*lightboxitem, data_uk_lightbox='counter: true', **kwargs) -> fastcore.xml.FT +[/code] + +> Lightbox container that will hold `LightboxItems` + +**Params** + + * `lightboxitem` `LightBoxItem`s that will be inside lightbox + + * `data_uk_lightbox` See https://franken-ui.dev/docs/2.0/lightbox for advanced options + + * `kwargs` + +**Returns:** Lightbox + +### LightboxItem + +Source + +[code] + + LightboxItem(*c, href, data_alt=None, data_caption=None, cls='', **kwargs) -> fastcore.xml.FT +[/code] + +> Anchor tag with appropriate structure to go inside a `LightBoxContainer` + +**Params** + + * `c` Component that when clicked will open the lightbox (often a button) + + * `href` Href to image, youtube video, vimeo, google maps, etc. + + * `data_alt` Alt text for the lightbox item/image + + * `data_caption` Caption for the item that shows below it + + * `cls` Class for the A tag (often nothing or `uk-btn`) + + * `kwargs` + +**Returns:** A(... href, data_alt, cls., ...) +# Lists API Reference + +See Source + +See Output + +#### disc List: + + * Item 1 + * Item 2 + +#### circle List: + + * Item 1 + * Item 2 + +#### square List: + + * Item 1 + * Item 2 + +#### decimal List: + + * Item 1 + * Item 2 + +#### hyphen List: + + * Item 1 + * Item 2 + +#### bullet List: + + * Item 1 + * Item 2 + +#### divider List: + + * Item 1 + * Item 2 + +#### striped List: + + * Item 1 + * Item 2 + +[code] + + def ex_lists(): + list_options = [(style,str(cls)) for style,cls in ListT.__members__.items()] + lists = [Div(H4(f"{style} List:"), Ul(Li("Item 1"), Li("Item 2"), cls=cls)) for style, cls in list_options] + return Grid(*lists) + +[/code] + +* * * + +### ListT + +_List styles using Tailwind CSS_ + +Option | Value | Option | Value | Option | Value +---|---|---|---|---|--- +disc | list-disc list-inside | circle | list-[circle] list-inside | square | list-[square] list-inside +decimal | uk-list uk-list-decimal | hyphen | uk-list uk-list-hyphen | bullet | uk-list uk-list-bullet +divider | uk-list uk-list-divider | striped | uk-list uk-list-striped | | +# Loading IndicatorsAPI Reference + +See Source + +See Output + +[code] + + def ex_loading1(): + return Loading() + +[/code] + +See Source + +See Output + +[code] + + def ex_loading2(): + types = [LoadingT.spinner, LoadingT.dots, LoadingT.ring, LoadingT.ball, LoadingT.bars, LoadingT.infinity] + sizes = [LoadingT.xs, LoadingT.sm, LoadingT.md, LoadingT.lg] + rows = [Div(*[Loading((t,s)) for s in sizes], cls='flex gap-4') for t in types] + return Div(*rows, cls='flex flex-col gap-4') + +[/code] + +### Loading + +Source + +[code] + + Loading(cls=(, ), htmx_indicator=False, **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a loading animation component + +**Params** + + * `cls` Classes for indicator (generally `LoadingT` options) + + * `htmx_indicator` Add htmx-indicator class + + * `kwargs` + +**Returns:** Span(cls=...) + +* * * + +### LoadingT + +__ + +Option | Value | Option | Value | Option | Value +---|---|---|---|---|--- +spinner | loading-spinner | dots | loading-dots | ring | loading-ring +ball | loading-ball | bars | loading-bars | infinity | loading-infinity +xs | loading-xsmall | sm | loading-small | md | loading-medium +lg | loading-large | | | | +# Markdown + automated HTML styling API Reference + +See Source + +See Output + +# Example Markdown + + * With **bold** and _italics_ + * With a link + +### And a subheading + +> This is a blockquote + +This supports inline latex: $e^{\pi i} + 1 = 0$ as well as block latex thanks to Katex. + +$$ \frac{1}{2\pi i} \oint_C \frac{f(z)}{z-z_0} dz $$ + +And even syntax highlighting thanks to Highlight.js! (Just make sure you set `highlightjs=True` in the headers function) + +[code] + + def add(a, b): + return a + b + +[/code] + +[code] + + def ex_markdown(): + md = '''# Example Markdown + + + With **bold** and *italics* + + With a [link](https://github.com) + + ### And a subheading + + > This is a blockquote + + This supports inline latex: $e^{\\pi i} + 1 = 0$ as well as block latex thanks to Katex. + + $$ + \\frac{1}{2\\pi i} \\oint_C \\frac{f(z)}{z-z_0} dz + $$ + + And even syntax highlighting thanks to Highlight.js! (Just make sure you set `highlightjs=True` in the headers function) + + ```python + def add(a, b): + return a + b + ``` + ''' + return render_md(md) + +[/code] + +You can overwrite the default styling for markdown rendering with your own css classes with `class_map + +See Source + +See Output + +With custom **bold** style + +> But no extra quote style because class_map overrides all default styled +[code] + + def ex_markdown2(): + md = '''With custom **bold** style\n\n > But no extra quote style because class_map overrides all default styled''' + return render_md(md, class_map={'b': 'text-red-500'}) + +[/code] + +You can modify the default styling for markdown rendering with your own css classes with `class_map_mods + +See Source + +See Output + +With custom **bold** style + +> But default quote style because class_map_mods replaces sepecified styles and leaves the rest as default +[code] + + def ex_markdown3(): + md = '''With custom **bold** style\n\n > But default quote style because class_map_mods replaces sepecified styles and leaves the rest as default''' + return render_md(md, class_map_mods={'b': 'text-red-500'}) + +[/code] + +This uses the `apply_classes` function, which can be used to apply classes to html strings. This is useful for applying styles to any html you get from an external source. + +See Source + +See Output + +

Hello, World!

This is a paragraph

+ +[code] + + def ex_applyclasses(): + return apply_classes('

Hello, World!

This is a paragraph

') + +[/code] + +One common external source is a markdown renderer. MonsterUI uses tailwind css for styling so you don't get any styling without specifying classes, `apply_classes` can do that for you. + +See Source + +See Output + +# Hi + +a link + +[code] + + def ex_applyclasses2(): + from mistletoe import markdown, HTMLRenderer + md = markdown('# Hi\n[a link](www.google.com)', renderer=HTMLRenderer) + return Safe(apply_classes(md)) + +[/code] + +### apply_classes + +Source + +[code] + + apply_classes(html_str: str, class_map=None, class_map_mods=None) -> str +[/code] + +> Apply classes to html string + +**Params** + + * `html_str` Html string + + * `class_map` Class map + + * `class_map_mods` Class map that will modify the class map map (useful for small changes to a base class map) + +**Returns:** Html string with classes applied +
# Modals API Reference + +### Example Modal + +This is a subtitle + +See Source + +See Output + +Open Modal + +## Simple Test Modal + +With some somewhat brief content to show that it works! + +Close + +[code] + + def ex_modal(): + return Div( + Button("Open Modal",data_uk_toggle="target: #my-modal" ), + Modal(ModalTitle("Simple Test Modal"), + P("With some somewhat brief content to show that it works!", cls=TextPresets.muted_sm), + footer=ModalCloseButton("Close", cls=ButtonT.primary),id='my-modal')) + +[/code] + +### Modal + +Source + +[code] + + Modal(*c, header=None, footer=None, cls=(), dialog_cls=(), header_cls='p-6', body_cls='space-y-6', footer_cls=(), id='', open=False, **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a modal with the appropriate classes to put the boilerplate in the appropriate places for you + +**Params** + + * `c` Components to put in the `ModalBody` (often forms, sign in buttons, images, etc.) + + * `header` Components that go in the `ModalHeader` (often a `ModalTitle`) + + * `footer` Components that go in the `ModalFooter` (often a `ModalCloseButton`) + + * `cls` Additional classes on the outermost `ModalContainer` + + * `dialog_cls` Additional classes on the `ModalDialog` + + * `header_cls` Additional classes on the `ModalHeader` + + * `body_cls` Additional classes on the `ModalBody` + + * `footer_cls` Additional classes on the `ModalFooter` + + * `id` id for the outermost container + + * `open` Whether the modal is open (typically used for HTMX controlled modals) + + * `kwargs` + +**Returns:** Fully styled modal FT Component + +### ModalCloseButton + +Source + +[code] + + ModalCloseButton(*c, cls=(), htmx=False, **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a button that closes a modal with js + +**Params** + + * `c` Components to put in the button (often text and/or an icon) + + * `cls` Additional classes on the button + + * `htmx` Whether to use HTMX to close the modal (must add hx_get to a route that closes the modal) + + * `kwargs` + +**Returns:** Button(..., cls='uk-modal-close') + `hx_target` and `hx_swap` if htmx is True + +The remainder of the Modal functions below are used internally by the `Modal` function for you. You shouldn't need to use them unless you're doing something really special. + +### ModalTitle + +Source + +[code] + + ModalTitle(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a modal title + +**Params** + + * `c` Components to put in the `ModalTitle` (often text) + + * `cls` Additional classes on the `ModalTitle` + + * `kwargs` + +**Returns:** H2(..., cls='uk-modal-title') + +### ModalFooter + +Source + +[code] + + ModalFooter(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a modal footer + +**Params** + + * `c` Components to put in the `ModalFooter` (often buttons) + + * `cls` Additional classes on the `ModalFooter` + + * `kwargs` + +**Returns:** Div(..., cls='uk-modal-footer') + +### ModalBody + +Source + +[code] + + ModalBody(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a modal body + +**Params** + + * `c` Components to put in the `ModalBody` (often forms, sign in buttons, images, etc.) + + * `cls` Additional classes on the `ModalBody` + + * `kwargs` + +**Returns:** Div(..., cls='uk-modal-body') + +### ModalHeader + +Source + +[code] + + ModalHeader(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a modal header + +**Params** + + * `c` Components to put in the `ModalHeader` + + * `cls` Additional classes on the `ModalHeader` + + * `kwargs` + +**Returns:** Div(..., cls='uk-modal-header') + +### ModalDialog + +Source + +[code] + + ModalDialog(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a modal dialog + +**Params** + + * `c` Components to put in the `ModalDialog` (often `ModalBody`, `ModalHeader`, etc) + + * `cls` Additional classes on the `ModalDialog` + + * `kwargs` + +**Returns:** Div(..., cls='uk-modal-dialog') + +### ModalContainer + +Source + +[code] + + ModalContainer(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a modal container that components go in + +**Params** + + * `c` Components to put in the modal (often `ModalDialog`) + + * `cls` Additional classes on the `ModalContainer` + + * `kwargs` + +**Returns:** Div(..., cls='uk-modal uk-modal-container') +# Navigation (Nav, NavBar, Tabs, etc.) API Reference + +# Nav, NavBar, DowDownNav, and Tab examples + +* * * + +## Nav + +See Source + +See Output + + * Option 1 + * Option 2 + * Option 3 + +[code] + + def ex_nav1(): + mbrs1 = [Li(A('Option 1'), cls='uk-active'), Li(A('Option 2')), Li(A('Option 3'))] + return NavContainer(*mbrs1) + +[/code] + +See Source + +See Output + + * NavHeaderLi + * Option 1 + * Option 2 + * Option 3 + * Subtitle Ex + +NavSubtitle text to be shown + + * * Parent Name + * Child 1 + * Child 2 + * Child 3 + +[code] + + def ex_nav2(): + mbrs1 = [Li(A('Option 1'), cls='uk-active'), Li(A('Option 2')), Li(A('Option 3'))] + mbrs2 = [Li(A('Child 1')), Li(A('Child 2')),Li(A('Child 3'))] + + return NavContainer( + NavHeaderLi("NavHeaderLi"), + *mbrs1, + Li(A(href='')(Div("Subtitle Ex",NavSubtitle("NavSubtitle text to be shown")))), + NavDividerLi(), + NavParentLi( + A('Parent Name'), + NavContainer(*mbrs2,parent=False), + ), + ) + +[/code] + +## Navbars + +Fully responsive simple navbar using the high level API. This will collapse to a hamburger menu on mobile devices. See the Scrollspy example for a more complex navbar example. + +See Source + +See Output + +### My Blog + +Page1Page2Page3 + +Page1Page2Page3 + +[code] + + def ex_navbar1(): + return NavBar(A("Page1",href='/rt1'), + A("Page2",href='/rt2'), + A("Page3",href='/rt3'), + brand=H3('My Blog')) + +[/code] + +See Source + +See Output + +Page1Page2 + +Page1Page2 + +[code] + + def ex_navbar2(): + return NavBar( + A(Input(placeholder='search')), + A(UkIcon("rocket")), + A('Page1',href='/rt1'), + A("Page2", href='/rt3'), + brand=DivLAligned(Img(src='/api_reference/logo.svg'),UkIcon('rocket',height=30,width=30))) + +[/code] + +## Drop Down Navs + +See Source + +See Output + +Open DropDown + + * Item 1 + * Item 2 + +[code] + + def ex_navdrop(): + return Div( + Button("Open DropDown"), + DropDownNavContainer(Li(A("Item 1",href=''),Li(A("Item 2",href=''))))) + +[/code] + +## Tabs + +See Source + +See Output + + * Active + * Item + * Item + * Disabled + +[code] + + def ex_tabs2(): + return Container( + TabContainer( + Li(A("Active",href='javascript:void(0);', cls='uk-active')), + Li(A("Item",href='javascript:void(0);')), + Li(A("Item",href='javascript:void(0);')), + Li(A("Disabled", cls='uk-disabled')))) + +[/code] + +A tabs can use any method of navigation (htmx, or href). However, often these are use in conjunction with switchers do to this client side + +See Source + +See Output + + * Active + * Item + * Item + * Disabled + + * # Tab 1 + + * # Tab 2 + + * # Tab 3 + +[code] + + def ex_tabs1(): + return Container( + TabContainer( + Li(A("Active",href='#', cls='uk-active')), + Li(A("Item",href='#')), + Li(A("Item",href='#')), + Li(A("Disabled",href='#', cls='uk-disabled')), + uk_switcher='connect: #component-nav; animation: uk-animation-fade', + alt=True), + Ul(id="component-nav", cls="uk-switcher")( + Li(H1("Tab 1")), + Li(H1("Tab 2")), + Li(H1("Tab 3")))) + +[/code] + +# API Docs + +### NavBar + +Source + +[code] + + NavBar(*c, brand=h3(('Title',),{'class': 'uk-h3 '}), right_cls='items-center space-x-4', mobile_cls='space-y-4', sticky: bool = False, uk_scrollspy_nav: bool | str = False, cls='p-4', scrollspy_cls=, menu_id=None) -> fastcore.xml.FT +[/code] + +> Creates a responsive navigation bar with mobile menu support + +**Params** + + * `c` Component for right side of navbar (Often A tag links) + + * `brand` Brand/logo component for left side + + * `right_cls` Spacing for desktop links + + * `mobile_cls` Spacing for mobile links + + * `sticky` Whether to stick to the top of the page while scrolling + + * `uk_scrollspy_nav` Whether to use scrollspy for navigation + + * `cls` Classes for navbar + + * `scrollspy_cls` Scrollspy class (usually ScrollspyT.*) + + * `menu_id` ID for menu container (used for mobile toggle) + +**Returns:** Responsive NavBar + +### TabContainer + +Source + +[code] + + TabContainer(*li, cls='', alt=False, **kwargs) -> fastcore.xml.FT +[/code] + +> A TabContainer where children will be different tabs + +**Params** + + * `li` Components + + * `cls` Additional classes on the `Ul` + + * `alt` Whether to use an alternative tab style + + * `kwargs` + +**Returns:** Tab container + +### NavContainer + +Source + +[code] + + NavContainer(*li, cls=, parent=True, uk_nav=False, uk_scrollspy_nav=False, sticky=False, **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a navigation container (useful for creating a sidebar navigation). A Nav is a list (NavBar is something different) + +**Params** + + * `li` List items are navigation elements (Special `Li` such as `NavParentLi`, `NavDividerLi`, `NavHeaderLi`, `NavSubtitle`, `NavCloseLi` can also be used) + + * `cls` Additional classes on the nav + + * `parent` Whether this nav is a _parent_ or _sub_ nav + + * `uk_nav` True for default collapsible behavior, see frankenui docs for more advanced options + + * `uk_scrollspy_nav` Activates scrollspy linking each item `A` tags `href` to content's `id` attribute + + * `sticky` Whether to stick to the top of the page while scrolling + + * `kwargs` + +**Returns:** FT Component that is a list of `Li` styled for a sidebar navigation menu + +* * * + +### NavT + +__ + +Option | Value | Option | Value +---|---|---|--- +default | uk-nav-default | primary | uk-nav-primary +secondary | uk-nav-secondary | | + +### NavCloseLi + +Source + +[code] + + NavCloseLi(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a navigation list item with a close button + +**Params** + + * `c` Components + + * `cls` Additional classes on the li + + * `kwargs` + +**Returns:** Navigation list item with a close button + +### NavSubtitle + +Source + +[code] + + NavSubtitle(*c, cls=, **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a navigation subtitle + +**Params** + + * `c` Components + + * `cls` Additional classes on the div + + * `kwargs` + +**Returns:** Navigation subtitle + +### NavHeaderLi + +Source + +[code] + + NavHeaderLi(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a navigation list item with a header + +**Params** + + * `c` Components + + * `cls` Additional classes on the li + + * `kwargs` + +**Returns:** Navigation list item with a header + +### NavDividerLi + +Source + +[code] + + NavDividerLi(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a navigation list item with a divider + +**Params** + + * `c` Components + + * `cls` Additional classes on the li + + * `kwargs` + +**Returns:** Navigation list item with a divider + +### NavParentLi + +Source + +[code] + + NavParentLi(*nav_container, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a navigation list item with a parent nav for nesting + +**Params** + + * `nav_container` `NavContainer` container for a nested nav with `parent=False`) + + * `cls` Additional classes on the li + + * `kwargs` + +**Returns:** Navigation list item + +### DropDownNavContainer + +Source + +[code] + + DropDownNavContainer(*li, cls=, parent=True, uk_nav=False, uk_dropdown=True, **kwargs) -> fastcore.xml.FT +[/code] + +> A Nav that is part of a DropDown + +**Params** + + * `li` Components + + * `cls` Additional classes on the nav + + * `parent` Whether to use a parent nav + + * `uk_nav` True for default collapsible behavior, see https://franken-ui.dev/docs/nav#component-options for more advanced options + + * `uk_dropdown` Whether to use a dropdown + + * `kwargs` + +**Returns:** DropDown nav container +# Alerts & Toasts API Reference + +### Alerts + +The simplest alert is a div wrapped with a span: + +See Source + +See Output + +This is a plain alert + +[code] + + def ex_alerts1(): return Alert("This is a plain alert") + +[/code] + +Alert colors are defined by the alert styles: + +See Source + +See Output + +Your purchase has been confirmed! + +[code] + + def ex_alerts2(): return Alert("Your purchase has been confirmed!", cls=AlertT.success) + +[/code] + +It often looks nice to use icons in alerts: + +See Source + +See Output + +Please enter a valid email. + +[code] + + def ex_alerts3(): + return Alert( + DivLAligned(UkIcon('triangle-alert'), + P("Please enter a valid email.")), + cls=AlertT.error) + +[/code] + +### Alert + +Source + +[code] + + Alert(*c, cls='', **kwargs) -> fastcore.xml.FT +[/code] + +> Alert informs users about important events. + +**Params** + + * `c` Content for Alert (often text and/or icon) + + * `cls` Class for the alert (often an `AlertT` option) + + * `kwargs` + +**Returns:** Div(Span(...), cls='alert', role='alert') + +* * * + +### AlertT + +_Alert styles from DaisyUI_ + +Option | Value | Option | Value +---|---|---|--- +info | alert-info | success | alert-success +warning | alert-warning | error | alert-error + +* * * + +### Toasts + +To define a toast with a particular location, add horizontal or vertical toast type classes: + +See Source + +See Output + +First Example Toast + +[code] + + def ex_toasts1(): + return Toast("First Example Toast", cls=(ToastHT.start, ToastVT.bottom)) + +[/code] + +To define toast colors, set the class of the alert wrapped by the toast: + +See Source + +See Output + +Second Example Toast + +[code] + + def ex_toasts2(): + return Toast("Second Example Toast", alert_cls=AlertT.info) + +[/code] + +### Toast + +Source + +[code] + + Toast(*c, cls='', alert_cls='', **kwargs) -> fastcore.xml.FT +[/code] + +> Toasts are stacked announcements, positioned on the corner of page. + +**Params** + + * `c` Content for toast (often test) + + * `cls` Classes for toast (often `ToastHT` and `ToastVT` options) + + * `alert_cls` classes for altert (often `AlertT` options) + + * `kwargs` + +**Returns:** Div(Alert(...), cls='toast') + +* * * + +### ToastHT + +_Horizontal position for Toast_ + +Option | Value | Option | Value +---|---|---|--- +start | toast-start | center | toast-center +end | toast-end | | + +* * * + +### ToastVT + +_Vertical position for Toast_ + +Option | Value | Option | Value +---|---|---|--- +top | toast-top | middle | toast-middle +bottom | toast-bottom | | +# Carousel Sliders API Reference + +Here is a simple example of a slider: + +See Source + +See Output + +[code] + + def ex_sliders_1(): + return Slider(*[Img(src=f'https://picsum.photos/200/200?random={i}') for i in range(10)]) + +[/code] + +Here is a slider with cards: + +See Source + +See Output + +### Card 0 + +Card 0 content + +### Card 1 + +Card 1 content + +### Card 2 + +Card 2 content + +### Card 3 + +Card 3 content + +### Card 4 + +Card 4 content + +### Card 5 + +Card 5 content + +### Card 6 + +Card 6 content + +### Card 7 + +Card 7 content + +### Card 8 + +Card 8 content + +### Card 9 + +Card 9 content + +[code] + + def ex_sliders_2(): + def _card(i): return Card(H3(f'Card {i}'), P(f'Card {i} content')) + return Slider(*[_card(i) for i in range(10)]) + +[/code] + +Here is a slider with cards and autoplay: + +See Source + +See Output + +### Card 0 + +Card 0 content + +### Card 1 + +Card 1 content + +### Card 2 + +Card 2 content + +### Card 3 + +Card 3 content + +### Card 4 + +Card 4 content + +### Card 5 + +Card 5 content + +### Card 6 + +Card 6 content + +### Card 7 + +Card 7 content + +### Card 8 + +Card 8 content + +### Card 9 + +Card 9 content + +[code] + + def ex_sliders_3(): + def _card(i): return Card(H3(f'Card {i}'), P(f'Card {i} content')) + return Slider(*[_card(i) for i in range(10)], items_cls='gap-10', uk_slider='autoplay: true; autoplay-interval: 1000') + +[/code] + +Typically you want to use the `Slider` component, but if you need more control you can use the `SliderContainer`, `SliderItems`, and `SliderNav` components. + +### Slider + +Source + +[code] + + Slider(*c, cls='', items_cls='gap-4', nav=True, nav_cls='', **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a slider with optional navigation arrows + +**Params** + + * `c` Items to show in slider + + * `cls` Classes for slider container + + * `items_cls` Classes for items container + + * `nav` Whether to show navigation arrows + + * `nav_cls` Classes for navigation arrows + + * `kwargs` + +**Returns:** SliderContainer(SliderItems(..., cls='gap-4'), SliderNav?) + +### SliderContainer + +Source + +[code] + + SliderContainer(*c, cls='', uk_slider=True, **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a slider container + +**Params** + + * `c` Components + + * `cls` Additional classes on the container + + * `uk_slider` See FrankenUI Slider docs for more options + + * `kwargs` + +**Returns:** Div(..., cls='relative', uk_slider=True, ...) + +### SliderItems + +Source + +[code] + + SliderItems(*c, cls='', **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a slider items container + +**Params** + + * `c` Components + + * `cls` Additional classes for the items + + * `kwargs` + +**Returns:** Div(..., cls='uk-slider-items uk-grid', ...) + +### SliderNav + +Source + +[code] + + SliderNav(cls='uk-position-small uk-hidden-hover', prev_cls='absolute left-0 top-1/2 -translate-y-1/2', next_cls='absolute right-0 top-1/2 -translate-y-1/2', **kwargs) -> fastcore.xml.FT +[/code] + +> Navigation arrows for Slider component + +**Params** + + * `cls` Additional classes for the navigation + + * `prev_cls` Additional classes for the previous navigation + + * `next_cls` Additional classes for the next navigation + + * `kwargs` + +**Returns:** Left and right navigation arrows for Slider component +# Steps API Reference + +See Source + +See Output + + * Account Created + * Profile Setup + * Verification + +[code] + + def ex_steps2(): + return Steps( + LiStep("Account Created", cls=StepT.primary), + LiStep("Profile Setup", cls=StepT.neutral), + LiStep("Verification", cls=StepT.neutral), + cls="w-full") + +[/code] + +See Source + +See Output + + * Project Planning + * Design Phase + * Development + * Testing + * Deployment + +[code] + + def ex_steps3(): + return Steps( + LiStep("Project Planning", cls=StepT.success, data_content="📝"), + LiStep("Design Phase", cls=StepT.success, data_content="💡"), + LiStep("Development", cls=StepT.primary, data_content="🛠️"), + LiStep("Testing", cls=StepT.neutral, data_content="🔎"), + LiStep("Deployment", cls=StepT.neutral, data_content="🚀"), + cls=(StepsT.vertical, "min-h-[400px]")) + +[/code] + +# API Docs + +### Steps + +Source + +[code] + + Steps(*li, cls='', **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a steps container + +**Params** + + * `li` Each `Li` represent a step (generally use `LiStep`) + + * `cls` class for Steps (generally a `StepsT` option) + + * `kwargs` + +**Returns:** Ul(..., cls='steps') + +* * * + +### StepsT + +_Options for Steps_ + +Option | Value | Option | Value +---|---|---|--- +vertical | steps-vertical | horizonal | steps-horizonal + +### LiStep + +Source + +[code] + + LiStep(*c, cls='', data_content=None, **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a step list item + +**Params** + + * `c` Description for Step that goes next to bubble (often text) + + * `cls` Additional step classes (generally a `StepT` component) + + * `data_content` Content for inside bubble (defaults to number, often an emoji) + + * `kwargs` + +**Returns:** Li(..., cls='step') + +* * * + +### StepT + +_Step styles for LiStep_ + +Option | Value | Option | Value | Option | Value +---|---|---|---|---|--- +primary | step-primary | secondary | step-secondary | accent | step-accent +info | step-info | success | step-success | warning | step-warning +error | step-error | neutral | step-neutral | | +# Tables API Reference + +See Source + +See Output + +Name | Age | City +---|---|--- +Alice | 25 | New York +Bob | 30 | San Francisco +Charlie | 35 | London +Total | 90 +[code] + + def ex_tables0(): + return Table( + Thead(Tr(Th('Name'), Th('Age'), Th('City'))), + Tbody(Tr(Td('Alice'), Td('25'), Td('New York')), + Tr(Td('Bob'), Td('30'), Td('San Francisco')), + Tr(Td('Charlie'), Td('35'), Td('London'))), + Tfoot(Tr(Td('Total'), Td('90')))) + +[/code] + +See Source + +See Output + +Name | Age | City +---|---|--- +Alice | 25 | New York +Bob | 30 | San Francisco +Charlie | 35 | London +Total | 90 +[code] + + def ex_tables1(): + header = ['Name', 'Age', 'City'] + body = [['Alice', '25', 'New York'], + ['Bob', '30', 'San Francisco'], + ['Charlie', '35', 'London']] + footer = ['Total', '90'] + return TableFromLists(header, body, footer) + +[/code] + +See Source + +See Output + +NAME | AGE | CITY +---|---|--- +Alice | 30 years | New York +Bob | 25 years | London +[code] + + def ex_tables2(): + def body_render(k, v): + match k.lower(): + case 'name': return Td(v, cls='font-bold') + case 'age': return Td(f"{v} years") + case _: return Td(v) + + header_data = ['Name', 'Age', 'City'] + body_data =[{'Name': 'Alice', 'Age': 30, 'City': 'New York'}, + {'Name': 'Bob', 'Age': 25, 'City': 'London'}] + + return TableFromDicts(header_data, body_data, + header_cell_render=lambda v: Th(v.upper()), + body_cell_render=body_render) + +[/code] + +### Table + +Source + +[code] + + Table(*c, cls=(, , , ), **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a table + +**Params** + + * `c` Components (typically `Thead`, `Tbody`, `Tfoot`) + + * `cls` Additional classes on the table + + * `kwargs` + +**Returns:** Table component + +### TableFromLists + +Source + +[code] + + TableFromLists(header_data: Sequence, body_data: Sequence[Sequence], footer_data=None, header_cell_render=, body_cell_render=, footer_cell_render=, cls=(, , , ), sortable=False, **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a Table from a list of header data and a list of lists of body data + +**Params** + + * `header_data` List of header data + + * `body_data` List of lists of body data + + * `footer_data` List of footer data + + * `header_cell_render` Function(content) -> FT that renders header cells + + * `body_cell_render` Function(key, content) -> FT that renders body cells + + * `footer_cell_render` Function(key, content) -> FT that renders footer cells + + * `cls` Additional classes on the table + + * `sortable` Whether to use sortable table + + * `kwargs` + +**Returns:** Table from lists + +### TableFromDicts + +Source + +[code] + + TableFromDicts(header_data: Sequence, body_data: Sequence[dict], footer_data=None, header_cell_render=, body_cell_render= at 0x7f7524465e40>, footer_cell_render= at 0x7f7524465ee0>, cls=(, , , ), sortable=False, **kwargs) -> fastcore.xml.FT +[/code] + +> Creates a Table from a list of header data and a list of dicts of body data + +**Params** + + * `header_data` List of header data + + * `body_data` List of dicts of body data + + * `footer_data` List of footer data + + * `header_cell_render` Function(content) -> FT that renders header cells + + * `body_cell_render` Function(key, content) -> FT that renders body cells + + * `footer_cell_render` Function(key, content) -> FT that renders footer cells + + * `cls` Additional classes on the table + + * `sortable` Whether to use sortable table + + * `kwargs` + +**Returns:** Styled Table + +* * * + +### TableT + +__ + +Option | Value | Option | Value | Option | Value +---|---|---|---|---|--- +divider | uk-table-divider | striped | uk-table-striped | hover | uk-table-hover +sm | uk-table-sm | lg | uk-table-lg | justify | uk-table-justify +middle | uk-table-middle | responsive | uk-table-responsive | | + +### Tbody + +Source + +[code] + + Tbody(*rows, cls=(), sortable=False, **kwargs) +[/code] + +> **Params** + + * `rows` + + * `cls` + + * `sortable` + + * `kwargs` + +### Th + +Source + +[code] + + Th(*c, cls=(), shrink=False, expand=False, small=False) +[/code] + +> **Params** + + * `c` Components that go in the cell + + * `cls` Additional classes on the cell container + + * `shrink` Whether to shrink the cell + + * `expand` Whether to expand the cell + + * `small` Whether to use a small table + +**Returns:** Table cell + +### Td + +Source + +[code] + + Td(*c, cls=(), shrink=False, expand=False, small=False) +[/code] + +> **Params** + + * `c` Components that go in the cell + + * `cls` Additional classes on the cell container + + * `shrink` Whether to shrink the cell + + * `expand` Whether to expand the cell + + * `small` Whether to use a small table + +**Returns:** Table cell +# Theme and Headers API Reference + +To get headers with a default theme use `hdrs=Theme..headers()`. For example for the blue theme you would use `hdrs=Theme.blue.headers()`. The theme integrated together different frameworks and allows tailwind, FrankenUI, HighlighJS, and DaisyUI components to work well together. + +Tailwind, FrankenUI and DaisyUI are imported by default. You must use DaisyUI headers to use anything in the `daisy` module, and FrankenUI headers to use anything in the `franken` module. + +HighlightJS is not added by default, but you can add it by setting `highlightjs=True` in the headers function. The `render_md` function will use HighlightJS for code blocks. + +Theme options are: + +Theme.slate + +Theme.stone + +Theme.gray + +Theme.neutral + +Theme.red + +Theme.rose + +Theme.orange + +Theme.green + +Theme.blue + +Theme.yellow + +Theme.violet + +Theme.zinc + +### Theme Picker + +See Source + +See Output + +ZincSlateStoneGrayNeutralRedRoseOrangeGreenBlueYellowVioletNoneSmallMediumLargeNoneSmallMediumLargeSmallDefaultLightDark + +[code] + + def ex_theme_switcher(): + return ThemePicker() + +[/code] + +### ThemePicker + +Source + +[code] + + ThemePicker(color=True, radii=True, shadows=True, font=True, mode=True, cls='p-4', custom_themes=[]) +[/code] + +> Theme picker component with configurable sections + +**Params** + + * `color` + + * `radii` + + * `shadows` + + * `font` + + * `mode` + + * `cls` + + * `custom_themes` + +Themes are controlled with `bg-background text-foreground` classes on the `Body` tag. `fast_app` and `FastHTML` will do this for you automatically so you typically do not have to do anything + +### fast_app + +Source + +[code] + + fast_app(*args, pico=False, db_file: Optional[str] = None, render: Optional[] = None, hdrs: Optional[tuple] = None, ftrs: Optional[tuple] = None, tbls: Optional[dict] = None, before: Union[tuple, NoneType, fasthtml.core.Beforeware] = None, middleware: Optional[tuple] = None, live: bool = False, debug: bool = False, routes: Optional[tuple] = None, exception_handlers: Optional[dict] = None, on_startup: Optional[] = None, on_shutdown: Optional[] = None, lifespan: Optional[] = None, default_hdrs=True, surreal: Optional[bool] = True, htmx: Optional[bool] = True, exts: Union[list, str, NoneType] = None, secret_key: Optional[str] = None, key_fname: str = '.sesskey', session_cookie: str = 'session_', max_age: int = 31536000, sess_path: str = '/', same_site: str = 'lax', sess_https_only: bool = False, sess_domain: Optional[str] = None, htmlkw: Optional[dict] = None, bodykw: Optional[dict] = None, reload_attempts: Optional[int] = 1, reload_interval: Optional[int] = 1000, static_path: str = '.', body_wrap: = , nb_hdrs: bool = False) +[/code] + +> Create a FastHTML or FastHTMLWithLiveReload app with `bg-background text-foreground` to bodykw for frankenui themes + +**Params** + + * `db_file` Database file name, if needed + + * `render` Function used to render default database class + + * `hdrs` Additional FT elements to add to + + * `ftrs` Additional FT elements to add to end of + + * `tbls` Experimental mapping from DB table names to dict table definitions + + * `before` Functions to call prior to calling handler + + * `middleware` Standard Starlette middleware + + * `live` Enable live reloading + + * `debug` Passed to Starlette, indicating if debug tracebacks should be returned on errors + + * `routes` Passed to Starlette + + * `exception_handlers` Passed to Starlette + + * `on_startup` Passed to Starlette + + * `on_shutdown` Passed to Starlette + + * `lifespan` Passed to Starlette + + * `default_hdrs` Include default FastHTML headers such as HTMX script? + + * `pico` Include PicoCSS header? + + * `surreal` Include surreal.js/scope headers? + + * `htmx` Include HTMX header? + + * `exts` HTMX extension names to include + + * `secret_key` Signing key for sessions + + * `key_fname` Session cookie signing key file name + + * `session_cookie` Session cookie name + + * `max_age` Session cookie expiry time + + * `sess_path` Session cookie path + + * `same_site` Session cookie same site policy + + * `sess_https_only` Session cookie HTTPS only? + + * `sess_domain` Session cookie domain + + * `htmlkw` Attrs to add to the HTML tag + + * `bodykw` Attrs to add to the Body tag + + * `reload_attempts` Number of reload attempts when live reloading + + * `reload_interval` Time between reload attempts in ms + + * `static_path` Where the static file route points to, defaults to root dir + + * `body_wrap` FT wrapper for body contents + + * `nb_hdrs` If in notebook include headers inject headers in notebook DOM? + + * `args` + +### FastHTML + +Source + +[code] + + FastHTML(*args, pico=False, debug=False, routes=None, middleware=None, title: str = 'FastHTML page', exception_handlers=None, on_startup=None, on_shutdown=None, lifespan=None, hdrs=None, ftrs=None, exts=None, before=None, after=None, surreal=True, htmx=True, default_hdrs=True, sess_cls=, secret_key=None, session_cookie='session_', max_age=31536000, sess_path='/', same_site='lax', sess_https_only=False, sess_domain=None, key_fname='.sesskey', body_wrap=, htmlkw=None, nb_hdrs=False) +[/code] + +> Create a FastHTML app and adds `bg-background text-foreground` to bodykw for frankenui themes + +**Params** + + * `debug` + + * `routes` + + * `middleware` + + * `title` + + * `exception_handlers` + + * `on_startup` + + * `on_shutdown` + + * `lifespan` + + * `hdrs` + + * `ftrs` + + * `exts` + + * `before` + + * `after` + + * `surreal` + + * `htmx` + + * `default_hdrs` + + * `sess_cls` + + * `secret_key` + + * `session_cookie` + + * `max_age` + + * `sess_path` + + * `same_site` + + * `sess_https_only` + + * `sess_domain` + + * `key_fname` + + * `body_wrap` + + * `htmlkw` + + * `nb_hdrs` + + * `args` + + * `pico` +# Typography API Reference + +Ready to go semantic options that cover most of what you need based on the HTML spec + +See Source + +See Output + +Titled + +# Titled + +# Level 1 Heading (H1) + +## Level 2 Heading (H2) + +### Level 3 Heading (H3) + +#### Level 4 Heading (H4) + +##### Level 5 Heading (H5) + +###### Level 6 Heading (H6) + +[code] + + def ex_headings(): + return Div( + Titled("Titled"), + H1("Level 1 Heading (H1)"), + H2("Level 2 Heading (H2)"), + H3("Level 3 Heading (H3)"), + H4("Level 4 Heading (H4)"), + H5("Level 5 Heading (H5)"), + H6("Level 6 Heading (H6)"), + ) + +[/code] + +See Source + +See Output + +## Semantic HTML Elements Demo + +Here's an example of _emphasized (Em)_ and **strong (Strong)** text. + +Some _italic text (I)_ and smaller text (Small) in a paragraph. + +You can highlight (Mark) text, show ~~deleted (Del)~~ and inserted (Ins) content. + +Chemical formulas use subscripts (Sub) and superscripts (Sup) like H2O. + +> The only way to do great work is to love what you do. +> +> Steve Jobs (Cite) + +As Shakespeare wrote, "All the world's a stage (Q)". + +Posted on 2024-01-29 + +Mozilla Foundation (Address) +331 E Evelyn Ave (Address) +Mountain View, CA 94041 (Address) +USA (Address) + +HTML (Dfn) (HyperText Markup Language (Abbr)) is the standard markup language for documents designed to be displayed in a web browser. + +Press `Ctrl (Kbd)` \+ `C (Kbd)` to copy. + +The command returned: Hello, World! (Samp) + +Let x (Var) be the variable in the equation. + +Figure 1: An example image with caption (Caption)Click to show more information (Summary) + +This is the detailed content that is initially hidden (P) + +123 (Data) is a number, and here's a Meter showing progress: + +Temperature: (with low/high/optimum values) + +€42.00 \- price example with semantic value + +Form calculation result: The sum is 42 (Output) + +### Blog Post Title (H3) + +By John Doe • 5 min read (Small) + +Article content here... + +This text has _proper name annotation (U)_ and this is ~~outdated information (S)~~ that's been superseded. + +[code] + + def ex_semantic_elements(): + return Div( + H2("Semantic HTML Elements Demo"), + # Text formatting examples + P("Here's an example of ", Em("emphasized (Em)"), " and ", Strong("strong (Strong)"), " text."), + P("Some ", I("italic text (I)"), " and ", Small("smaller text (Small)"), " in a paragraph."), + P("You can ", Mark("highlight (Mark)"), " text, show ", Del("deleted (Del)"), " and ", + Ins("inserted (Ins)"), " content."), + P("Chemical formulas use ", Sub("subscripts (Sub)"), " and ", Sup("superscripts (Sup)"), + " like H", Sub("2"), "O."), + # Quote examples + Blockquote( + P("The only way to do great work is to love what you do."), + Cite("Steve Jobs (Cite)")), + P("As Shakespeare wrote, ", Q("All the world's a stage (Q)"), "."), + # Time and Address + P("Posted on ", Time("2024-01-29", datetime="2024-01-29")), + Address( + "Mozilla Foundation (Address)", + Br(), + "331 E Evelyn Ave (Address)", + Br(), + "Mountain View, CA 94041 (Address)", + Br(), + "USA (Address)"), + # Technical and definition examples + P( + Dfn("HTML (Dfn)"), " (", + Abbr("HyperText Markup Language (Abbr)", title="HyperText Markup Language"), + ") is the standard markup language for documents designed to be displayed in a web browser."), + P("Press ", Kbd("Ctrl (Kbd)"), " + ", Kbd("C (Kbd)"), " to copy."), + P("The command returned: ", Samp("Hello, World! (Samp)")), + P("Let ", Var("x (Var)"), " be the variable in the equation."), + # Figure with caption + Figure( + PicSumImg(), + Caption("Figure 1: An example image with caption (Caption)")), + # Interactive elements + Details( + Summary("Click to show more information (Summary)"), + P("This is the detailed content that is initially hidden (P)")), + # Data representation + P( + Data("123 (Data)", value="123"), " is a number, and here's a Meter showing progress: ", + Meter(value=0.6, min=0, max=1)), + P( + "Temperature: ", + Meter(value=-1, min=-10, max=40, low=0, high=30, optimum=21), + " (with low/high/optimum values)"), + P( + Data("€42.00", value="42"), + " - price example with semantic value"), + # Output example + P("Form calculation result: ", Output("The sum is 42 (Output)", form="calc-form", for_="num1 num2")), + # Meta information example + Section( + H3("Blog Post Title (H3)"), + Small("By John Doe • 5 min read (Small)"), + P("Article content here...")), + # Text decoration examples + P("This text has ",U("proper name annotation (U)"), " and this is ",S("outdated information (S)"), " that's been superseded."), + cls='space-y-4' + ) + +[/code] + +See Source + +See Output + +`This is a CodeSpan element` + +> This is a blockquote element +[code] + + #This is a CodeBlock element + + def add(a,b): return a+b +[/code] + +[code] + + def ex_other(): + return Div( + CodeSpan("This is a CodeSpan element"), + Blockquote("This is a blockquote element"), + CodeBlock("#This is a CodeBlock element\n\ndef add(a,b): return a+b")) + +[/code] + +Styling text is possibly the most common style thing to do, so we have a couple of helpers for discoverability inside python. `TextPresets` is intended to be combinations are are widely applicable and used often, where `TextT` is intended to be more flexible options for you to combine together yourself. + +##### TextPresets.* + +See Source + +See Output + +This is muted_sm text + +This is muted_lg text + +This is bold_sm text + +This is bold_lg text + +This is md_weight_sm text + +This is md_weight_muted text + +[code] + + def ex_textpresets(): + return Grid(*[Div(P(f"This is {preset.name} text", cls=preset.value)) for preset in TextPresets]) + +[/code] + +##### TextT.* + +See Source + +See Output + +This is paragraph text + +This is lead text + +This is meta text + +This is gray text + +This is italic text + +This is xs text + +This is sm text + +This is lg text + +This is xl text + +This is light text + +This is normal text + +This is medium text + +This is bold text + +This is extrabold text + +This is primary text + +This is secondary text + +This is success text + +This is warning text + +This is error text + +This is info text + +This is left text + +This is right text + +This is center text + +This is justify text + +This is start text + +This is end text + +This is top text + +This is middle text + +This is bottom text + +This is truncate text + +This is break_ text + +This is nowrap text + +This is underline text + +This is highlight text + +[code] + + def ex_textt(): + return Grid(*[Div(P(f"This is {s.name} text", cls=s.value)) for s in TextT]) + +[/code] + +### API Reference + +* * * + +### TextPresets + +_Common Typography Presets_ + +Option | Value | Option | Value +---|---|---|--- +muted_sm | text-gray-500 dark:text-gray-200 text-sm | muted_lg | text-gray-500 dark:text-gray-200 text-lg +bold_sm | font-bold text-sm | bold_lg | font-bold text-lg +md_weight_sm | text-sm font-medium | md_weight_muted | font-medium text-gray-500 dark:text-gray-200 + +* * * + +### TextT + +_Text Styles from https://franken-ui.dev/docs/text_ + +Option | Value | Option | Value | Option | Value | Option | Value +---|---|---|---|---|---|---|--- +paragraph | uk-paragraph | lead | uk-text-lead | meta | uk-text-meta | gray | text-gray-500 dark:text-gray-200 +italic | italic | xs | text-xs | sm | text-sm | lg | text-lg +xl | text-xl | light | font-normal | normal | font-light | medium | font-medium +bold | font-bold | extrabold | font-extrabold | muted | text-gray-500 dark:text-gray-200 | primary | text-primary +secondary | text-secondary | success | text-success | warning | text-warning | error | text-error +info | text-info | left | text-left | right | text-right | center | text-center +justify | text-justify | start | text-start | end | text-end | top | align-top +middle | align-middle | bottom | align-bottom | truncate | uk-text-truncate | break_ | uk-text-break +nowrap | uk-text-nowrap | underline | underline | highlight | bg-yellow-200 dark:bg-yellow-800 text-black | | + +### H1 + +Source + +[code] + + H1(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> H1 with styling and appropriate size + +**Params** + + * `c` Contents of H1 tag (often text) + + * `cls` Classes in addition to H1 styling + + * `kwargs` + +**Returns:** H1(..., cls='uk-h1') + +### H2 + +Source + +[code] + + H2(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> H2 with styling and appropriate size + +**Params** + + * `c` Contents of H2 tag (often text) + + * `cls` Classes in addition to H2 styling + + * `kwargs` + +**Returns:** H2(..., cls='uk-h2') + +### H3 + +Source + +[code] + + H3(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> H3 with styling and appropriate size + +**Params** + + * `c` Contents of H3 tag (often text) + + * `cls` Classes in addition to H3 styling + + * `kwargs` + +**Returns:** H3(..., cls='uk-h3') + +### H4 + +Source + +[code] + + H4(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> H4 with styling and appropriate size + +**Params** + + * `c` Contents of H4 tag (often text) + + * `cls` Classes in addition to H4 styling + + * `kwargs` + +**Returns:** H4(..., cls='uk-h4') + +### H5 + +Source + +[code] + + H5(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> H5 with styling and appropriate size + +**Params** + + * `c` Contents of H5 tag (often text) + + * `cls` Classes in addition to H5 styling + + * `kwargs` + +**Returns:** H5(..., cls='text-lg font-semibold') + +### H6 + +Source + +[code] + + H6(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> H6 with styling and appropriate size + +**Params** + + * `c` Contents of H6 tag (often text) + + * `cls` Classes in addition to H6 styling + + * `kwargs` + +**Returns:** H6(..., cls='text-base font-semibold') + +### CodeSpan + +Source + +[code] + + CodeSpan(*c, cls=(), **kwargs) -> fastcore.xml.FT +[/code] + +> A CodeSpan with Styling + +**Params** + + * `c` Contents of CodeSpan tag (inline text code snippets) + + * `cls` Classes in addition to CodeSpan styling + + * `kwargs` + +**Returns:** Code(..., cls='uk-codespan') + +### Blockquote + +Source + +[code] + + Blockquote(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Blockquote with Styling + +**Params** + + * `c` Contents of Blockquote tag (often text) + + * `cls` Classes in addition to Blockquote styling + + * `kwargs` + +**Returns:** Blockquote(..., cls='uk-blockquote') + +### CodeBlock + +Source + +[code] + + CodeBlock(*c: str, cls: enum.Enum | str | tuple = (), code_cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> CodeBlock with Styling + +**Params** + + * `c` Contents of Code tag (often text) + + * `cls` Classes for the outer container + + * `code_cls` Classes for the code tag + + * `kwargs` + +**Returns:** Div(Pre(Code(..., cls='uk-codeblock), cls='multiple tailwind styles'), cls='uk-block') + +### Em + +Source + +[code] + + Em(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled emphasis text + +**Params** + + * `c` Contents of Em tag (emphasis) + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Em tag + +### Strong + +Source + +[code] + + Strong(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled strong text + +**Params** + + * `c` Contents of Strong tag + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Strong tag + +### I + +Source + +[code] + + I(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled italic text + +**Params** + + * `c` Contents of I tag (italics) + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for I tag + +### Small + +Source + +[code] + + Small(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled small text + +**Params** + + * `c` Contents of Small tag + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Small tag + +### Mark + +Source + +[code] + + Mark(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled highlighted text + +**Params** + + * `c` Contents of Mark tag (highlighted text) + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Mark tag + +### Sub + +Source + +[code] + + Sub(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled subscript text + +**Params** + + * `c` Contents of Sub tag (subscript) + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Sub tag + +### Sup + +Source + +[code] + + Sup(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled superscript text + +**Params** + + * `c` Contents of Sup tag (superscript) + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Sup tag + +### Del + +Source + +[code] + + Del(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled deleted text + +**Params** + + * `c` Contents of Del tag (deleted text) + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Del tag + +### Ins + +Source + +[code] + + Ins(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled inserted text + +**Params** + + * `c` Contents of Ins tag (inserted text) + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Ins tag + +### Dfn + +Source + +[code] + + Dfn(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled definition term with italic and medium weight + +**Params** + + * `c` Contents of Dfn tag (definition) + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Dfn tag + +### Abbr + +Source + +[code] + + Abbr(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), title: str = None, **kwargs) -> fastcore.xml.FT +[/code] + +> Styled abbreviation with dotted underline + +**Params** + + * `c` Contents of Abbr tag + + * `cls` Additional classes + + * `title` Title attribute for abbreviation + + * `kwargs` + +**Returns:** Additional args for Abbr tag + +### Q + +Source + +[code] + + Q(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled quotation mark + +**Params** + + * `c` Contents of Q tag (quote) + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Q tag + +### Kbd + +Source + +[code] + + Kbd(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled keyboard input with subtle background + +**Params** + + * `c` Contents of Kbd tag (keyboard input) + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Kbd tag + +### Samp + +Source + +[code] + + Samp(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled sample output with subtle background + +**Params** + + * `c` Contents of Samp tag (sample output) + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Samp tag + +### Var + +Source + +[code] + + Var(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled variable with italic monospace + +**Params** + + * `c` Contents of Var tag (variable) + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Var tag + +### Figure + +Source + +[code] + + Figure(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled figure container with card-like appearance + +**Params** + + * `c` Contents of Figure tag + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Figure tag + +### Caption + +Source + +[code] + + Caption(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled caption text + +**Params** + + * `c` + + * `cls` + + * `kwargs` + +### Details + +Source + +[code] + + Details(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled details element + +**Params** + + * `c` Contents of Details tag + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Details tag + +### Summary + +Source + +[code] + + Summary(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled summary element + +**Params** + + * `c` Contents of Summary tag + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Summary tag + +### Meter + +Source + +[code] + + Meter(*c: fastcore.xml.FT | str, value: float = None, min: float = None, max: float = None, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled meter element + +**Params** + + * `c` Contents of Meter tag + + * `value` Current value + + * `min` Minimum value + + * `max` Maximum value + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Meter tag + +### Data + +Source + +[code] + + Data(*c: fastcore.xml.FT | str, value: str = None, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled data element + +**Params** + + * `c` Contents of Data tag + + * `value` Value attribute + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Data tag + +### Output + +Source + +[code] + + Output(*c: fastcore.xml.FT | str, form: str = None, for_: str = None, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled output element for form results + +**Params** + + * `c` Contents of Output tag + + * `form` ID of form this output belongs to + + * `for_` IDs of elements this output is for + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Output tag + +### Address + +Source + +[code] + + Address(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), **kwargs) -> fastcore.xml.FT +[/code] + +> Styled address element + +**Params** + + * `c` Contents of Address tag + + * `cls` Additional classes + + * `kwargs` + +**Returns:** Additional args for Address tag + +### Time + +Source + +[code] + + Time(*c: fastcore.xml.FT | str, cls: enum.Enum | str | tuple = (), datetime: str = None, **kwargs) -> fastcore.xml.FT +[/code] + +> Styled time element + +**Params** + + * `c` Contents of Time tag + + * `cls` Additional classes + + * `datetime` datetime attribute + + * `kwargs` + +**Returns:** Additional args for Time tag + + *[HyperText Markup Language (Abbr)]: HyperText Markup Language +# MonterUI Page Layout Guide + +This guide will discuss 3 tools for laying out your app pages, Grid, Flexbox, and Columns. This page will discuss the strengths and when to use each individually, and then a section for how to combine them for more complex layouts at the end. + +> Note: This guide is designed to get you started building layouts quickly, not to teach you all the details needed to build every possible custom layout with pixel-perfect control. To get more detailed and lower-level control, explore the tailwind docs. + +This guide is for creating flexible layouts you envision, but does not discuss responsiveness to make different layouts that are both mobile and desktop friendly. Stay tunes for a responsiveness guide that will help with that! + +# Grid + +Grids are best for regular predictable layouts with lots of the same shape of things that may need to change a lot for different screen sizes. I think the best way to see what it can do is to see a bunch of examples, so here they are! + +## Minimal Image Cards + +This is a minimal example of a grid that just shows image and text. This is the foundation for many more complex layouts so make sure to understand what's going on here first before moving on! + +A grid lays things out in a...grid. As you can see, we have evenly sized cards by default. + +See Source + +See Output + +Image 0 + +Image 1 + +Image 2 + +Image 3 + +Image 4 + +Image 5 + +[code] + + def picsum_img(seed): return Img(src=f'https://picsum.photos/300/200?random={seed}') + + Grid(*[Card(picsum_img(i),P(f"Image {i}")) for i in range(6)]) +[/code] + +## Dashboard Example + +However, they don't have to be evenly sized! By providing `row-span-{int}` and `col-span-{int}` we can control how many rows or columns specific grid elements take up. By doing this, we can create a grid that has lots of different shapes and types of elements. + +Let's look at a dashboard layout at an examples of this. + +See Source + +See Output + +### SideBar + +Range For Filters + +A search Bar + +Choose Product Line + +Product Line AProduct Line BProduct Line CProduct Line D + +Include Inactive Users + +Include Users without order + +Include Users without email + +Total Users + +### 1,234 + +Active Now + +### 342 + +Revenue + +### $45,678 + +Conversion + +### 2.4% + +### Monthly Revenue + +Chart Goes Here + +### User Growth + +Chart Goes Here + +[code] + + def StatCard(title, value, color='primary'): + "A card with a statistics. Since there is no row/col span class it will take up 1 slot" + return Card(P(title, cls=TextPresets.muted_sm), H3(value, cls=f'text-{color}'),) + + stats = [StatCard(*data) for data in [ + ("Total Users", "1,234", "blue-600"), + ("Active Now", "342", "green-600"), + ("Revenue", "$45,678", "purple-600"), + ("Conversion", "2.4%", "amber-600")]] + + def ChartCard(title): + "A card for a chart. col-span-2 means it will take up 2 columns" + return Div(cls="col-span-2")( + Card(H3(title),Div("Chart Goes Here", cls="h-64 uk-background-muted"))) + chart_cards = [ChartCard(title) for title in ("Monthly Revenue", "User Growth")] + + + sidebar = Form( + H3("SideBar"), + LabelRange("Range For Filters", min=0, max=100), + LabelInput("A search Bar"), + LabelSelect(map(Option, ["Product Line A", "Product Line B", "Product Line C", "Product Line D"]), + label="Choose Product Line"), + LabelCheckboxX("Include Inactive Users"), + LabelCheckboxX("Include Users without order"), + LabelCheckboxX("Include Users without email"), + # This sidebar will take up 2 rows b/c of row-span-2 + cls='row-span-2 space-y-5' + ) + + Container(Grid(sidebar, *stats, *chart_cards, cols=5)) +[/code] + +# Flexbox + +Using Grid for the overall layout, and flex for the individual elements is a powerful pattern. With `MonsterUI` you can do quite a bit without knowing anything about flexbox, which is what will be taught here. + +However, flexbox is well worth learning about it in more detail. You will run into situations where you need more flexbox knowledge than is covered here to build your vision. Thankfully you can get that knowledge by playing a fantastic tutorial game called FlexBox Froggy! + +## Forms + +Often you want to stack things horizontally. You can use the `DivHStacked` component to do this. + +`DivHStacked` is a helper function for flexbox and creates a div with these classes by default `cls=(FlexT.block, FlexT.row, FlexT.middle, 'space-x-4')`. + +See Source + +See Output + +### Form with Input Groups + +Search Users + +Filter Tags + +Email List + +SubmitCancel + +[code] + + def InputGroup(label, placeholder='', button_text='Submit', cls=''): + # Div H Stacked makes the label and input show up on the same row instead of putting the input on a newline + return DivHStacked( + FormLabel(label, cls='whitespace-nowrap'), + Input(placeholder=placeholder)) + + Container( + H3("Form with Input Groups"), + Form(cls='space-y-4')( + InputGroup("Search Users", "Enter username..."), + InputGroup("Filter Tags", "Add tags...", "Add"), + InputGroup("Email List", "Enter email...", "Subscribe"), + Div(*( Button(UkIcon(icon, cls='mr-2'), text) for icon, text in [("rocket", "Submit"), ("circle-x", "Cancel")]), cls='space-x-4'))) +[/code] + +## Avatar + +You can use this same `DivHStacked` to align things like text next to images. And you can use `DivVStacked` to stack things vertically to create design structures you like. `DivVStacked` works by using `cls=(FlexT.block,FlexT.column,FlexT.middle)` + +See Source + +See Output + +John Doe + +[email protected] + ++1-123-456-7890 + +[code] + + # DivHStacked makes the a single row so text is to on same line as avatar + DivHStacked( + DiceBearAvatar("user"), + # DivVStacked stacks things vertically together and centers it with flex + DivVStacked( + P("John Doe", cls=TextT.lg), + P("[email protected]", cls=TextT.muted), + P("+1-123-456-7890"), cls=TextT.muted)) +[/code] + +## Pricing Card + +These can be combined with icons and other styling to create larger components like a pricing card. + +See Source + +See Output + +## Pro Plan + +### $99 + +per month + + * Unlimited users + + * 24/7 priority support + + * Custom branding options + + * Advanced analytics dashboard + + * Full API access + + * Priority request queue + +Subscribe Now + +[code] + + features = [ + "Unlimited users", + "24/7 priority support", + "Custom branding options", + "Advanced analytics dashboard", + "Full API access", + "Priority request queue" + ] + + + def PricingCard(plan, price, features): + "Create a polished pricing card with consistent styling" + return Card( + DivVStacked( # Center and veritcally stack the plan name and price + H2(plan), + H3(price, cls='text-primary'), + P('per month',cls=TextT.muted), + cls='space-y-1'), + # DivHStacked makes green check and feature Li show up on same row instead of newline + Ul(*[DivHStacked(UkIcon('check', cls='text-green-500 mr-2'), Li(feature)) for feature in features], + cls='space-y-4'), + Button("Subscribe Now", cls=(ButtonT.primary, 'w-full'))) + + DivVStacked(PricingCard("Pro Plan", "$99", features)) +[/code] + +## Footer + +Or you can combine things to make advanced footers that have titles, organized links, and icons! + +In this example we add another flex helper function, `DivFullySpaced`. `DivFullySpaced` is a flex class that puts as much space between items as possible + +See Source + +See Output + +### Company Name + +* * * + +#### Company + +AboutBlogCareersPress Kit + +#### Resources + +DocumentationHelp CenterStatusContact Sales + +#### Legal + +Terms of ServicePrivacy PolicyCookie SettingsAccessibility + +* * * + +© 2024 Company Name. All rights reserved. + +[code] + + def FooterLinkGroup(title, links): + # DivVStacked centers and makes title and each link stack vertically + return DivVStacked( + H4(title), + *[A(text, href=f"#{text.lower().replace(' ', '-')}", cls=TextT.muted) for text in links]) + + company = ["About", "Blog", "Careers", "Press Kit"] + resource = ["Documentation", "Help Center", "Status", "Contact Sales"] + legal = ["Terms of Service", "Privacy Policy", "Cookie Settings", "Accessibility"] + + Container(cls='uk-background-muted py-12')(Div( + # Company Name and social icons will be on the same row with as much sapce between as possible + DivFullySpaced( + H3("Company Name"), + # DivHStacked makes the icons be on the same row in a group + DivHStacked(*[UkIcon(icon, cls=TextT.lead) for icon in + ['twitter', 'facebook', 'github', 'linkedin']])), + DividerLine(), + DivFullySpaced( # Each child will be spread out as much as possible based on number of children + FooterLinkGroup("Company", company), + FooterLinkGroup("Resources", resource), + FooterLinkGroup("Legal", legal)), + DividerLine(), + P("© 2024 Company Name. All rights reserved.", cls=TextT.lead+TextT.sm), + cls='space-y-8 p-8')) +[/code] + +## Dashboard + +See Source + +See Output + +## Welcome back, Isaac! + +Here's what's happening with your projects today. + +Total Projects + +### 12 + ++2.5% from last month + +Hours Logged + +### 164 + ++12.3% from last month + +Tasks Complete + +### 64% + +-4.1% from last month + +Team Velocity + +### 23 + ++8.4% from last month + +### Recent Activity + +Sarah Chen completed Project Alpha deployment + +2h ago + +James Wilson commented on Project Beta + +4h ago + +Maria Garcia uploaded new design files + +6h ago + +Alex Kumar started Sprint Planning + +8h ago + +[code] + + def StatsCard(label, value, change): + color = 'green' if change[0] == '+' else 'red' + return Card(DivVStacked( # Stacks vertically and centers all elements + P(label, cls=TextPresets.muted_sm), + H3(value), + P(f"{change}% from last month", cls=f"text-{color}-600 text-sm"))) + + def RecentActivity(user, action, time): + return DivHStacked( # Makes Avatar and text be on same row + DiceBearAvatar(user, h=8, w=8), + P(f"{user} {action}", cls="flex-1"), + P(time, cls=TextPresets.muted_sm)) + + DivVStacked( # Centers the entire dashboard layout + # Page header + DivVStacked( # Stacks vertically and centers the title/subtitle + H2("Welcome back, Isaac!"), + P("Here's what's happening with your projects today.",cls=TextT.muted)), + + # DivHStacked puts all the stats cards on the same row + DivHStacked(*(StatsCard(label, value, change) + for label, value, change in [ + ("Total Projects", "12", "+2.5"), + ("Hours Logged", "164", "+12.3"), + ("Tasks Complete", "64%", "-4.1"), + ("Team Velocity", "23", "+8.4")] + )), + + # Recent activity + Card(*(RecentActivity(user, action, time) + for user, action, time in [ + ("Sarah Chen", "completed Project Alpha deployment", "2h ago"), + ("James Wilson", "commented on Project Beta", "4h ago"), + ("Maria Garcia", "uploaded new design files", "6h ago"), + ("Alex Kumar", "started Sprint Planning", "8h ago")]), + header=H3("Recent Activity"), + ), + cls="space-y-6" + ) +[/code] + +## Columns + +Columns are a great for sections that have a lot of text. + +See Source + +See Output + +# Lorem Ipsum + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + +Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. + +Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium. + +Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor. + +[code] + + Container( + H1("Lorem Ipsum", cls="text-center mb-8"), + + # Use 2 columns for the main content + Div(cls="columns-2 gap-12")( + P("""Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad + minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip + ex ea commodo consequat."""), + + DivCentered(cls='mt-8')( + P("""Duis aute irure dolor in reprehenderit in voluptate velit esse + cillum dolore eu fugiat nulla pariatur.""", + cls=(TextT.lg, TextT.bold, TextT.center, TextT.italic, "text-primary"))), + + P("""Excepteur sint occaecat cupidatat non proident, sunt in culpa qui + officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde + omnis iste natus error sit voluptatem accusantium doloremque laudantium."""), + + P("""Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit + aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem + sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor."""))) +[/code] +# Padding & Margin & Spacing, Oh my! (MonsterUI Spacing Guide) + +This guide will cover some essentials about how to properly space apps and what the differences are between: + + * Padding + * Margin + * Spacing + * Gap + +Manipulating the space between components can make a huge difference to the percieved quality of the page. Being able to tweak the spacing can have a big impact! + +> Tip: I find it works best to get everything on the page without adjusting spacing much, and adjusting spacing at the end. + +## Abreviations: + +First a few abbreviations that are helpful to know with tailwind (and a convention we follow in `MonsterUI`). + + * `t`, `b`, `l`, `r` = top, bottom, left, right + * `p`, `m` = padding, margin + * `x`, `y` = horizontal, vertical + +That means: + + * `mt` means margin on top of the element + * `px` means padding on the x axis (both left and right) + * `space-y` means apply spacing on the y axis (both top and bottom) + +## Padding vs Margin + +Margin applies space to the left of the component, and padding applies space on the left inside of the component. + +Please reference the example with cards below: + + * `ml-20` applies space to the left of the card (outside the card) + * `pl-20` applies space on the left inside of the card (inside the card) + +This means that if you want to move the whole thing but keep the actual container unchanged, use margin. If you want to change the container by adding space inside of it, use padding. + +See Source + +See Output + +#### A Simple Card with ml-20 + +#### A Simple Card with pl-20 + +[code] + + Grid( + Card(H4("A Simple Card with ml-20",style='background-color: red'), + cls='ml-20'), + Card(H4("A Simple Card with pl-20", style='background-color: red'), + cls='pl-20')) +[/code] + +## Space vs gap + +Spacing and gap are both about setting the space between components. + + * Spacing applies margin to every element except for the first element in a group. + * Gap creates a gap between every element in flexbox elements and grids. + +> Rule of thumb: Use Gap when using grids. + +Let's take a look at some grid examples. + +#### Grid + +See Source + +See Output + +#### A Simple Card + +#### A Simple Card + +#### A Simple Card + +#### A Simple Card + +#### A Simple Card + +#### A Simple Card + +[code] + + Grid( + Card(H4("A Simple Card")), + Card(H4("A Simple Card")), + Card(H4("A Simple Card")), + Card(H4("A Simple Card")), + Card(H4("A Simple Card")), + Card(H4("A Simple Card")), + cls='') +[/code] + +#### Grid with gap + +See Source + +See Output + +#### A Simple Card + +#### A Simple Card + +#### A Simple Card + +#### A Simple Card + +#### A Simple Card + +#### A Simple Card + +[code] + + Grid( + Card(H4("A Simple Card")), + Card(H4("A Simple Card")), + Card(H4("A Simple Card")), + Card(H4("A Simple Card")), + Card(H4("A Simple Card")), + Card(H4("A Simple Card")), + cls='gap-4') +[/code] + +#### Grid with space + +See Source + +See Output + +#### A Simple Card + +#### A Simple Card + +#### A Simple Card + +#### A Simple Card + +#### A Simple Card + +#### A Simple Card + +[code] + + Grid( + Card(H4("A Simple Card")), + Card(H4("A Simple Card")), + Card(H4("A Simple Card")), + Card(H4("A Simple Card")), + Card(H4("A Simple Card")), + Card(H4("A Simple Card")), + cls='space-x-4 space-y-4') +[/code] + +### Grid with no gap or space + +The first example has no gap or not space applied. As expected this means the cards are flush with each other. Often this is not what you want, because a little space between cards looks much nicer. + +### Grid with gap + +The second example has the same grid but with gap applied. As youc an see, this gives constent space between all elements of the grid looks great! + +### Grid with space + +The third example has the same grid but with space applied. As you can see, it's not really what we want. However it's a really good illustration of how space works so let's notice a few things about it: + +**X Axis** + + * The first card is flush with the left side of the page (no margin) + * The card below it isn't flush with the left side of the page (has margin) + +**Y Axis** + + * The first card is flush with the heading immediately above it (no margin) + * The card top it's right isn't flush with the heading above it (has margin) + +So `space` applies margin to every element except for the first element in a group! + +> Tip: Use your browser developer tools to inspect the examples + +Next, let's look at a form example where `gap` isn't a good choice but `space` works beautifully! + +See Source + +See Output + +### My Form + +Name + +Phone + +Email + +[code] + + Form(DivCentered(H3("My Form")), + LabelInput("Name"), + Grid(LabelInput("Phone"), LabelInput("Email"), cols=2), + cls='') +[/code] + +See Source + +See Output + +### My Form with gap + +Name + +Phone + +Email + +[code] + + Form(DivCentered(H3("My Form with gap")), + LabelInput("Name"), + Grid(LabelInput("Phone"), LabelInput("Email"), cols=2), + cls='gap-y-5') +[/code] + +See Source + +See Output + +### My Form with Spacing + +Name + +Phone + +Email + +[code] + + Form(DivCentered(H3("My Form with Spacing")), + LabelInput("Name"), + Grid(LabelInput("Phone"), LabelInput("Email"), cols=2), + cls='space-y-5') +[/code] + +### Form with no gap or space + +The top form looks a bit scrunched with defaults, but it's certainly passable. There is a bit of a space between the label and it's associated input because of the defaults in MonsterUI. + +### Form with gap + +The second form with gap is identical to the first. Because we're not in a flex element or a grid, it doesn't do anything at all! + +### Form with space + +`Space-y-5` adds vertical space between each child which really spreads out the form for a nice aesthetic. If you recall from the grid example, it does not apply this margin to the first element - but in this situation (and many others) we do not want the spacing above the top element (heading) to be the same as the spacing between the form elements. + +> Tip: Use your browser developer tools to inspect the examples + +# Further reading + +For further reading, check out the Tailwind CSS guide, which other users have found to be a useful as an additional guide. +