diff --git a/solara/autorouting.py b/solara/autorouting.py index 57bf4b132..5fdb0be96 100644 --- a/solara/autorouting.py +++ b/solara/autorouting.py @@ -185,9 +185,10 @@ def get_args(f): else: return [] - if isinstance(route_current.data, Path): + if str(route_current.file).endswith(".md") or isinstance(route_current.data, Path): path = cast(Path, route_current.data) if path.suffix == ".md": + component = route_current.component or solara.Markdown with solara.HBox() as navigation: if routes_siblings_index > 0: prev = routes_siblings[routes_siblings_index - 1] @@ -207,9 +208,11 @@ def get_args(f): solara.Button( icon_name="mdi-pencil", icon=True, href=url, target="_blank", style={"position": "absolute", "top": "0px", "right": "0px"} ) - solara.Markdown(path.read_text(), unsafe_solara_execute=True) + # solara.Markdown(path.read_text(), unsafe_solara_execute=True) + component(path.read_text(), unsafe_solara_execute=True) else: - content = solara.Markdown(path.read_text(), unsafe_solara_execute=True) + # content = solara.Markdown(path.read_text(), unsafe_solara_execute=True) + content = component(path.read_text(), unsafe_solara_execute=True) main = solara.Div( classes=["solara-autorouter-content"], @@ -313,6 +316,11 @@ def get_page(module: ModuleType, required=True): return page +def get_markdown_renderer(module: ModuleType): + markdown_renderer = getattr(module, "MarkdownRenderer", None) + return markdown_renderer + + def get_renderable(module: ModuleType, required=False): var_names = "app Page page".split() for var_name in var_names: @@ -438,7 +446,7 @@ def generate_routes(module: ModuleType) -> List[solara.Route]: return routes -def generate_routes_directory(path: Path) -> List[solara.Route]: +def generate_routes_directory(path: Path, markdown_renderer=None) -> List[solara.Route]: """Generate routes for a directory. This is a recursive function that will generate routes for all @@ -463,6 +471,7 @@ def generate_routes_directory(path: Path) -> List[solara.Route]: if init.exists(): init_module = source_to_module(init) layout = getattr(init_module, "Layout", None) + markdown_renderer = get_markdown_renderer(init_module) or markdown_renderer suffixes = [".py", ".ipynb", ".md"] for subpath in subpaths: @@ -471,13 +480,13 @@ def generate_routes_directory(path: Path) -> List[solara.Route]: continue if subpath.stem.startswith("_") or subpath.stem.startswith("."): continue - route = _generate_route_path(subpath, layout=layout, first=first, has_index=has_index) + route = _generate_route_path(subpath, layout=layout, first=first, has_index=has_index, markdown_renderer=markdown_renderer) first = False routes.append(route) return routes -def _generate_route_path(subpath: Path, layout=None, first=False, has_index=False, initial_namespace={}) -> solara.Route: +def _generate_route_path(subpath: Path, layout=None, first=False, has_index=False, initial_namespace={}, markdown_renderer=None) -> solara.Route: from .server import reload name = subpath.stem @@ -497,6 +506,7 @@ def _generate_route_path(subpath: Path, layout=None, first=False, has_index=Fals module_layout = layout if first else None if subpath.suffix == ".md": data = subpath + component = markdown_renderer reload.reloader.watcher.add_file(subpath) elif subpath.is_dir(): children = generate_routes_directory(subpath) diff --git a/solara/website/components/markdown.py b/solara/website/components/markdown.py new file mode 100644 index 000000000..3d909ac68 --- /dev/null +++ b/solara/website/components/markdown.py @@ -0,0 +1,30 @@ +from typing import Dict, List, Union + +import yaml + +import solara + + +# We want to separate metadata from the markdown files before rendering them, which solara.Markdown doesn't support +@solara.component +def MarkdownWithMetadata(content: str, unsafe_solara_execute=True): + if "---" in content: + pre_content, raw_metadata, post_content = content.split("---") + metadata: Dict[str, Union[str, List[str]]] = yaml.safe_load(raw_metadata) + + if len(pre_content) == 0: + content = post_content + else: + content = pre_content + post_content + + if "title" not in metadata.keys(): + metadata["title"] = content.split("#")[1].split("\n")[0] + + for key, value in metadata.items(): + if key == "title": + solara.Title(value) + elif ":" in key: + solara.Meta(property=key, content=value) + else: + solara.Meta(name=key, content=value) + solara.Markdown(content, unsafe_solara_execute=unsafe_solara_execute)