> 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/ - `def AccordionItem(title, *c)` Creates a single item for use within an Accordion component, handling title, content, and open state. - `def Accordion(*c, **kwargs)` Creates a styled Accordion container using accordion component. - `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()