Spaces:
Sleeping
Sleeping
| <project title="MonsterUI Documentation">> MonsterUI is a python library which brings styling to python for FastHTML apps.<api reference><doc title="API List" desc="Complete API Reference"># 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, icons, daisy, highlightjs, katex, apex_charts, radii, shadows, font)` | |
| Create frankenui and tailwind cdns | |
| - `local_headers(self, mode, static_dir, icons, daisy, highlightjs, katex, apex_charts, 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, destructive | |
| - `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 | |
| - `class FrankenRenderer` | |
| Custom renderer for Franken UI that handles image paths | |
| - `def __init__(self, *args, **kwargs)` | |
| - `def render_image(self, token)` | |
| Modify image paths if they're relative and self.img_dir is specified | |
| - `def render_md(md_content, class_map, class_map_mods, img_dir, renderer)` | |
| Renders markdown using mistletoe and lxml with custom image handling | |
| - `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` | |
| - `def ApexChart(**kws)` | |
| Apex chart component | |
| </doc></api reference><examples><doc title="Cards" desc="FrankenUI Cards Example built with MonsterUI (original design by ShadCN)">"""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()</doc><doc title="Dashboard" desc="FrankenUI Dashboard Example built with MonsterUI (original design by ShadCN)">"""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()</doc><doc title="Forms" desc="FrankenUI Forms Example built with MonsterUI (original design by ShadCN)">"""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()</doc><doc title="Scrollspy" desc="MonsterUI Scrollspy Example application">"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()</doc><doc title="Ticket" desc="MonsterUI Help Desk Example - Professional Dashboard with DaisyUI components">"""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()</doc><doc title="Playground" desc="FrankenUI Playground Example built with MonsterUI (original design by ShadCN)">"""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()</doc><doc title="Mail" desc="FrankenUI Mail Example built with MonsterUI (original design by ShadCN)">"""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()</doc><doc title="Tasks" desc="FrankenUI Tasks Example built with MonsterUI (original design by ShadCN)">"""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()</doc><doc title="Music" desc="FrankenUI Music Example build with MonsterUI (Original design by ShadCN)">"""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)))), | |
| brand=DivLAligned(H2("Purrify")) | |
| ) | |
| # 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()</doc><doc title="Auth" desc="FrankenUI Auth Example built with MonsterUI (original design by ShadCN)">"""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()</doc></examples></project> | |