Spaces:
Running
Running
| # Disable import sort ordering due to the hack needed | |
| # to ensure local imports. | |
| # ruff: noqa: E402 | |
| import base64 | |
| import inspect | |
| import os | |
| import sys | |
| from dataclasses import dataclass | |
| from typing import Literal | |
| import mesop as me | |
| # Append the current directory to sys.path to ensure local imports work | |
| # This is required so mesop/examples/__init__.py can import the modules | |
| # imported below. | |
| current_dir = os.path.dirname(os.path.abspath(__file__)) | |
| if current_dir not in sys.path: | |
| sys.path.append(current_dir) | |
| import glob | |
| import audio as audio | |
| import autocomplete as autocomplete | |
| import badge as badge | |
| import basic_animation as basic_animation | |
| import bootstrap as bootstrap | |
| import box as box | |
| import button as button | |
| import button_toggle as button_toggle | |
| import card as card | |
| import chat as chat | |
| import chat_inputs as chat_inputs | |
| import checkbox as checkbox | |
| import code_demo as code_demo # cannot call it code due to python library naming conflict | |
| import date_picker as date_picker | |
| import date_range_picker as date_range_picker | |
| import density as density | |
| import dialog as dialog | |
| import divider as divider | |
| import embed as embed | |
| import expansion_panel as expansion_panel | |
| import fancy_chat as fancy_chat | |
| import feedback as feedback | |
| import form_billing as form_billing | |
| import form_profile as form_profile | |
| import grid_table as grid_table | |
| import headers as headers | |
| import html_demo as html_demo | |
| import icon as icon | |
| import image as image | |
| import input as input | |
| import link as link | |
| import llm_playground as llm_playground | |
| import llm_rewriter as llm_rewriter | |
| import markdown_demo as markdown_demo # cannot call it markdown due to python library naming conflict | |
| import markdown_editor as markdown_editor | |
| import plot as plot | |
| import progress_bar as progress_bar | |
| import progress_spinner as progress_spinner | |
| import radio as radio | |
| import select_demo as select_demo # cannot call it select due to python library naming conflict | |
| import sidenav as sidenav | |
| import slide_toggle as slide_toggle | |
| import slider as slider | |
| import snackbar as snackbar | |
| import tab_group as tab_group | |
| import table as table | |
| import tailwind as tailwind | |
| import text as text | |
| import text_to_image as text_to_image | |
| import text_to_text as text_to_text | |
| import textarea as textarea | |
| import tooltip as tooltip | |
| import uploader as uploader | |
| import video as video | |
| class Example: | |
| # module_name (should also be the path name) | |
| name: str | |
| class Section: | |
| name: str | |
| examples: list[Example] | |
| FIRST_SECTIONS = [ | |
| Section( | |
| name="Quick start", | |
| examples=[ | |
| Example(name="chat"), | |
| Example(name="text_to_image"), | |
| Example(name="text_to_text"), | |
| ], | |
| ), | |
| Section( | |
| name="Use cases", | |
| examples=[ | |
| Example(name="fancy_chat"), | |
| Example(name="llm_rewriter"), | |
| Example(name="llm_playground"), | |
| Example(name="markdown_editor"), | |
| ], | |
| ), | |
| Section( | |
| name="Patterns", | |
| examples=[ | |
| Example(name="dialog"), | |
| Example(name="grid_table"), | |
| Example(name="headers"), | |
| Example(name="snackbar"), | |
| Example(name="tab_group"), | |
| Example(name="chat_inputs"), | |
| Example(name="form_billing"), | |
| Example(name="form_profile"), | |
| ], | |
| ), | |
| Section( | |
| name="Features", | |
| examples=[ | |
| Example(name="density"), | |
| ], | |
| ), | |
| Section( | |
| name="Misc", | |
| examples=[ | |
| Example(name="basic_animation"), | |
| Example(name="feedback"), | |
| ], | |
| ), | |
| Section( | |
| name="Integrations", | |
| examples=[ | |
| Example(name="bootstrap"), | |
| Example(name="tailwind"), | |
| ], | |
| ), | |
| ] | |
| COMPONENTS_SECTIONS = [ | |
| Section( | |
| name="Layout", | |
| examples=[ | |
| Example(name="box"), | |
| Example(name="sidenav"), | |
| ], | |
| ), | |
| Section( | |
| name="Text", | |
| examples=[ | |
| Example(name="text"), | |
| Example(name="markdown_demo"), | |
| Example(name="code_demo"), | |
| ], | |
| ), | |
| Section( | |
| name="Media", | |
| examples=[ | |
| Example(name="image"), | |
| Example(name="audio"), | |
| Example(name="video"), | |
| ], | |
| ), | |
| Section( | |
| name="Form", | |
| examples=[ | |
| Example(name="autocomplete"), | |
| Example(name="button"), | |
| Example(name="button_toggle"), | |
| Example(name="checkbox"), | |
| Example(name="date_picker"), | |
| Example(name="date_range_picker"), | |
| Example(name="input"), | |
| Example(name="textarea"), | |
| Example(name="radio"), | |
| Example(name="select_demo"), | |
| Example(name="slide_toggle"), | |
| Example(name="slider"), | |
| Example(name="uploader"), | |
| ], | |
| ), | |
| Section( | |
| name="Visual", | |
| examples=[ | |
| Example(name="badge"), | |
| Example(name="card"), | |
| Example(name="divider"), | |
| Example(name="expansion_panel"), | |
| Example(name="icon"), | |
| Example(name="progress_bar"), | |
| Example(name="progress_spinner"), | |
| Example(name="table"), | |
| Example(name="tooltip"), | |
| ], | |
| ), | |
| Section( | |
| name="Web", | |
| examples=[ | |
| Example(name="embed"), | |
| Example(name="html_demo"), | |
| Example(name="link"), | |
| ], | |
| ), | |
| Section( | |
| name="Others", | |
| examples=[ | |
| Example(name="plot"), | |
| ], | |
| ), | |
| ] | |
| ALL_SECTIONS = FIRST_SECTIONS + COMPONENTS_SECTIONS | |
| BORDER_SIDE = me.BorderSide( | |
| style="solid", | |
| width=1, | |
| color="#dcdcdc", | |
| ) | |
| class State: | |
| current_demo: str | |
| panel_fullscreen: Literal["preview", "editor", None] = None | |
| screenshots: dict[str, str] = {} | |
| def load_home_page(e: me.LoadEvent): | |
| if me.state(ThemeState).dark_mode: | |
| me.set_theme_mode("dark") | |
| else: | |
| me.set_theme_mode("system") | |
| yield | |
| screenshot_dir = os.path.join(current_dir, "screenshots") | |
| screenshot_files = glob.glob(os.path.join(screenshot_dir, "*.webp")) | |
| for screenshot_file in screenshot_files: | |
| image_name = os.path.basename(screenshot_file).split(".")[0] | |
| with open(screenshot_file, "rb") as image_file: | |
| encoded_string = base64.b64encode(image_file.read()).decode() | |
| screenshots[image_name] = "data:image/webp;base64," + encoded_string | |
| yield | |
| def main_page(): | |
| header() | |
| with me.box( | |
| style=me.Style( | |
| background=me.theme_var("background"), | |
| flex_grow=1, | |
| display="flex", | |
| ) | |
| ): | |
| if is_desktop(): | |
| side_menu() | |
| with me.box( | |
| style=me.Style( | |
| width="calc(100% - 150px)" if is_desktop() else "100%", | |
| display="flex", | |
| gap=24, | |
| flex_direction="column", | |
| padding=me.Padding.all(24), | |
| overflow_y="auto", | |
| ) | |
| ): | |
| with me.box( | |
| style=me.Style( | |
| height="calc(100vh - 120px)", | |
| ) | |
| ): | |
| for section in ALL_SECTIONS: | |
| with me.box(style=me.Style(margin=me.Margin(bottom=28))): | |
| me.text( | |
| section.name, | |
| style=me.Style( | |
| font_weight=500, | |
| font_size=20, | |
| margin=me.Margin( | |
| bottom=16, | |
| ), | |
| ), | |
| ) | |
| with me.box( | |
| style=me.Style( | |
| display="flex", | |
| flex_direction="row", | |
| flex_wrap="wrap", | |
| gap=28, | |
| ) | |
| ): | |
| for example in section.examples: | |
| example_card(example.name) | |
| def navigate_example_card(e: me.ClickEvent): | |
| me.navigate("/embed/" + e.key) | |
| def example_card(name: str): | |
| with me.box( | |
| key=name, | |
| on_click=navigate_example_card, | |
| style=me.Style( | |
| border=me.Border.all( | |
| me.BorderSide( | |
| width=1, | |
| color="rgb(220, 220, 220)", | |
| style="solid", | |
| ) | |
| ), | |
| box_shadow="rgba(0, 0, 0, 0.2) 0px 3px 1px -2px, rgba(0, 0, 0, 0.14) 0px 2px 2px, rgba(0, 0, 0, 0.12) 0px 1px 5px", | |
| cursor="pointer", | |
| width="min(100%, 150px)", | |
| border_radius=12, | |
| background=me.theme_var("background"), | |
| ), | |
| ): | |
| image_url = screenshots.get(name, "") | |
| me.box( | |
| style=me.Style( | |
| background=f'url("{image_url}") center / cover', | |
| height=112, | |
| width=150, | |
| ) | |
| ) | |
| me.text( | |
| format_example_name(name), | |
| style=me.Style( | |
| font_weight=500, | |
| font_size=18, | |
| padding=me.Padding.all(12), | |
| border=me.Border( | |
| top=me.BorderSide( | |
| width=1, | |
| style="solid", | |
| color="rgb(220, 220, 220)", | |
| ) | |
| ), | |
| ), | |
| ) | |
| def on_load_embed(e: me.LoadEvent): | |
| if me.state(ThemeState).dark_mode: | |
| me.set_theme_mode("dark") | |
| else: | |
| me.set_theme_mode("system") | |
| if not is_desktop(): | |
| me.state(State).panel_fullscreen = "preview" | |
| def create_main_fn(example: Example): | |
| def main(): | |
| with me.box( | |
| style=me.Style( | |
| height="100%", | |
| display="flex", | |
| flex_direction="column", | |
| background=me.theme_var("background"), | |
| ) | |
| ): | |
| header(demo_name=example.name) | |
| body(example.name) | |
| return main | |
| for section in FIRST_SECTIONS + COMPONENTS_SECTIONS: | |
| for example in section.examples: | |
| create_main_fn(example) | |
| def body(current_demo: str): | |
| state = me.state(State) | |
| with me.box( | |
| style=me.Style( | |
| flex_grow=1, | |
| display="flex", | |
| ) | |
| ): | |
| if is_desktop(): | |
| side_menu() | |
| src = "/" + current_demo | |
| with me.box( | |
| style=me.Style( | |
| width="calc(100% - 150px)" if is_desktop() else "100%", | |
| display="grid", | |
| grid_template_columns="1fr 1fr" | |
| if state.panel_fullscreen is None | |
| else "1fr", | |
| ) | |
| ): | |
| if state.panel_fullscreen != "editor": | |
| demo_ui(src) | |
| if state.panel_fullscreen != "preview": | |
| demo_code(inspect.getsource(get_module(current_demo))) | |
| def demo_ui(src: str): | |
| state = me.state(State) | |
| with me.box( | |
| style=me.Style(flex_grow=1), | |
| ): | |
| with me.box( | |
| style=me.Style( | |
| display="flex", | |
| justify_content="space-between", | |
| align_items="center", | |
| border=me.Border(bottom=BORDER_SIDE), | |
| ) | |
| ): | |
| me.text( | |
| "Preview", | |
| style=me.Style( | |
| font_weight=500, | |
| padding=me.Padding.all(14), | |
| ), | |
| ) | |
| if is_desktop(): | |
| with me.tooltip( | |
| position="above", | |
| message="Minimize" | |
| if state.panel_fullscreen == "preview" | |
| else "Maximize", | |
| ): | |
| with me.content_button(type="icon", on_click=toggle_fullscreen): | |
| me.icon( | |
| "close_fullscreen" | |
| if state.panel_fullscreen == "preview" | |
| else "fullscreen" | |
| ) | |
| else: | |
| swap_button() | |
| me.embed( | |
| src=src, | |
| style=me.Style( | |
| border=me.Border.all(me.BorderSide(width=0)), | |
| border_radius=2, | |
| height="calc(100vh - 106px)", | |
| width="100%", | |
| ), | |
| ) | |
| def swap_button(): | |
| state = me.state(State) | |
| with me.tooltip( | |
| position="above", | |
| message="Swap for code" | |
| if state.panel_fullscreen == "preview" | |
| else "Swap for preview", | |
| ): | |
| with me.content_button(type="icon", on_click=swap_fullscreen): | |
| me.icon("swap_horiz") | |
| def swap_fullscreen(e: me.ClickEvent): | |
| state = me.state(State) | |
| if state.panel_fullscreen == "preview": | |
| state.panel_fullscreen = "editor" | |
| else: | |
| state.panel_fullscreen = "preview" | |
| def toggle_fullscreen(e: me.ClickEvent): | |
| state = me.state(State) | |
| if state.panel_fullscreen == "preview": | |
| state.panel_fullscreen = None | |
| else: | |
| state.panel_fullscreen = "preview" | |
| def demo_code(code_arg: str): | |
| with me.box( | |
| style=me.Style( | |
| flex_grow=1, | |
| overflow_x="hidden", | |
| overflow_y="hidden", | |
| border=me.Border( | |
| left=BORDER_SIDE, | |
| ), | |
| background=me.theme_var("surface-container-low"), | |
| ) | |
| ): | |
| with me.box( | |
| style=me.Style( | |
| display="flex", | |
| justify_content="space-between", | |
| align_items="center", | |
| border=me.Border(bottom=BORDER_SIDE), | |
| background=me.theme_var("background"), | |
| ) | |
| ): | |
| me.text( | |
| "Code", | |
| style=me.Style( | |
| font_weight=500, | |
| padding=me.Padding.all(14), | |
| ), | |
| ) | |
| if not is_desktop(): | |
| swap_button() | |
| # Use four backticks for code fence to avoid conflicts with backticks being used | |
| # within the displayed code. | |
| me.markdown( | |
| f"""````python | |
| {code_arg} | |
| ```` | |
| """, | |
| style=me.Style( | |
| border=me.Border( | |
| right=BORDER_SIDE, | |
| ), | |
| font_size=13, | |
| height="calc(100vh - 106px)", | |
| overflow_y="auto", | |
| width="100%", | |
| ), | |
| ) | |
| def header(demo_name: str | None = None): | |
| with me.box( | |
| style=me.Style( | |
| border=me.Border( | |
| bottom=me.BorderSide( | |
| style="solid", | |
| width=1, | |
| color="#dcdcdc", | |
| ) | |
| ), | |
| overflow_x="clip", | |
| ) | |
| ): | |
| with me.box( | |
| style=me.Style( | |
| display="flex", | |
| align_items="end", | |
| justify_content="space-between", | |
| margin=me.Margin(left=12, right=12, bottom=12), | |
| font_size=24, | |
| ) | |
| ): | |
| with me.box(style=me.Style(display="flex")): | |
| with me.box( | |
| style=me.Style(display="flex", cursor="pointer"), | |
| on_click=navigate_home, | |
| ): | |
| me.text( | |
| "Mesop", style=me.Style(font_weight=700, margin=me.Margin(right=8)) | |
| ) | |
| me.text("Demos ") | |
| if demo_name: | |
| me.text( | |
| "— " + format_example_name(demo_name), | |
| style=me.Style(white_space="nowrap", text_overflow="ellipsis"), | |
| ) | |
| with me.box(style=me.Style(display="flex", align_items="baseline")): | |
| with me.box( | |
| style=me.Style( | |
| display="flex", | |
| align_items="baseline", | |
| ), | |
| ): | |
| me.link( | |
| text="mesop-dev/mesop", | |
| url="https://github.com/mesop-dev/mesop/", | |
| open_in_new_tab=True, | |
| style=me.Style( | |
| font_size=18, | |
| color=me.theme_var("primary"), | |
| text_decoration="none", | |
| margin=me.Margin(left=8, right=4, bottom=-16, top=-16), | |
| ), | |
| ) | |
| me.text( | |
| "v" + me.__version__, | |
| style=me.Style(font_size=18, margin=me.Margin(left=16)), | |
| ) | |
| with me.content_button( | |
| type="icon", | |
| style=me.Style(left=8, right=4, top=4), | |
| on_click=toggle_theme, | |
| ): | |
| me.icon( | |
| "light_mode" if me.theme_brightness() == "dark" else "dark_mode" | |
| ) | |
| class ThemeState: | |
| dark_mode: bool | |
| def toggle_theme(e: me.ClickEvent): | |
| if me.theme_brightness() == "light": | |
| me.set_theme_mode("dark") | |
| me.state(ThemeState).dark_mode = True | |
| else: | |
| me.set_theme_mode("light") | |
| me.state(ThemeState).dark_mode = False | |
| def navigate_home(e: me.ClickEvent): | |
| me.navigate("/") | |
| def side_menu(): | |
| with me.box( | |
| style=me.Style( | |
| padding=me.Padding.all(12), | |
| width=150, | |
| flex_grow=0, | |
| line_height="1.5", | |
| border=me.Border(right=BORDER_SIDE), | |
| overflow_x="hidden", | |
| height="calc(100vh - 60px)", | |
| overflow_y="auto", | |
| ) | |
| ): | |
| for section in FIRST_SECTIONS: | |
| nav_section(section) | |
| with me.box( | |
| style=me.Style( | |
| margin=me.Margin.symmetric( | |
| horizontal=-16, | |
| vertical=16, | |
| ), | |
| ) | |
| ): | |
| me.divider() | |
| me.text( | |
| "Components", | |
| style=me.Style( | |
| letter_spacing="0.5px", | |
| margin=me.Margin(bottom=6), | |
| ), | |
| ) | |
| for section in COMPONENTS_SECTIONS: | |
| nav_section(section) | |
| def nav_section(section: Section): | |
| with me.box(style=me.Style(margin=me.Margin(bottom=12))): | |
| me.text(section.name, style=me.Style(font_weight=700)) | |
| for example in section.examples: | |
| example_name = format_example_name(example.name) | |
| path = f"/embed/{example.name}" | |
| with me.box( | |
| style=me.Style(color=me.theme_var("primary"), cursor="pointer"), | |
| on_click=set_demo, | |
| key=path, | |
| ): | |
| me.text(example_name) | |
| def set_demo(e: me.ClickEvent): | |
| me.navigate(e.key) | |
| def format_example_name(name: str): | |
| return ( | |
| (" ".join(name.split("_"))) | |
| .capitalize() | |
| .replace("Llm", "LLM") | |
| .replace(" demo", "") | |
| ) | |
| def get_module(module_name: str): | |
| if module_name in globals(): | |
| return globals()[module_name] | |
| raise me.MesopDeveloperException(f"Module {module_name} not supported") | |
| def is_desktop(): | |
| return me.viewport_size().width > 760 | |