Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat, docs: Improve SEO by adding metadata #568

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions solara/autorouting.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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"],
Expand Down Expand Up @@ -438,7 +441,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_component=None) -> List[solara.Route]:
"""Generate routes for a directory.

This is a recursive function that will generate routes for all
Expand Down Expand Up @@ -471,13 +474,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_component=markdown_component)
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_component=None) -> solara.Route:
from .server import reload

name = subpath.stem
Expand All @@ -497,9 +500,10 @@ 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_component
reload.reloader.watcher.add_file(subpath)
elif subpath.is_dir():
children = generate_routes_directory(subpath)
children = generate_routes_directory(subpath, markdown_component=markdown_component)
else:
reload.reloader.watcher.add_file(subpath)
module = source_to_module(subpath, initial_namespace=initial_namespace)
Expand Down
30 changes: 30 additions & 0 deletions solara/website/components/markdown.py
Original file line number Diff line number Diff line change
@@ -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)
31 changes: 2 additions & 29 deletions solara/website/pages/documentation/advanced/__init__.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,9 @@
from pathlib import Path

import solara
from solara.autorouting import generate_routes_directory
from solara.website.components.markdown import MarkdownWithMetadata

title = "Advanced"
HERE = Path(__file__)
# if we didn't put the content in the subdirectory, but pointed to the current file
# we would include the current file recursively, causing an infinite loop
routes = generate_routes_directory(HERE.parent / "content")


@solara.component
def Page(route_external=None):
solara.Markdown(Path(HERE.parent / "content" / "10-howto" / "00-overview.md").read_text())

with solara.Row(justify="center", style={"flex-wrap": "wrap", "align-items": "start"}):
for child in route_external.children:
if child.path == "/":
continue

card_title = solara.Link("/documentation/advanced/" + child.path, children=[child.label])

with solara.Card(title=card_title, style={"min-width": "300px"}):
with solara.v.List():
with solara.v.ListItemGroup():
for grandchild in child.children:
if grandchild.path == "/":
continue
with solara.Link(
"/documentation/advanced/" + child.path + "/" + grandchild.path
if child.path != "/"
else "/documentation/advanced/" + grandchild.path
):
with solara.v.ListItem():
solara.v.ListItemTitle(children=[grandchild.label])
iisakkirotko marked this conversation as resolved.
Show resolved Hide resolved
routes = generate_routes_directory(HERE.parent / "content", MarkdownWithMetadata)
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
---
title: Overview of how-to articles
description: The how-tos are meant as deeper dives into specific topics from various perspectives
---

The how-tos are meant as deeper dives into specific topics. Although we try to write each how-to as a standalone document, some parts of a how-to may build on top of a previous one.
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
title: Building multi-page apps in Solara
description: The simplest way to create a multi-page app is to create a directory with multiple scripts.
---

# Multi-page support

In the [Web App tutorial](/documentation/getting_started/tutorials/web-app), we created an application consisting of a single page. Web applications generally have multiple pages, and Solara supports this as well.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
title: Making different layouts in Solara
description: Solara comes with a layout system ideal for data apps. Learn how to use them in this short guide.
---

# Layout

Solara comes with a layout system ideal for data apps.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
title: Testing your Solara application, both front and back end
description: Using solara you can test both the front and back end functionalities of your application.
---

# Testing with Solara
# Testing Application Logic

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@

---
title: Debugging Solara applications
description: You can use the Python debugger to debug your Solara app.
---
# Debugging

## PDB
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
---
title: Embedding Solara applications into existing websites
description: Solara can be embedded into existing websites. Although it is technically possible to embed a Solara app into an existing webpage,
we currently support embedding primarily via iframes.
---

# Embedding in existing websites

Solara can be embedded into existing websites. Although it is technically possible to embed a Solara app into an existing webpage, we currently support embedding primarily via iframes.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
title: Using various ipywidgets libraries within a Solara application
description: Solara can work with virtually any ipywidget library, and enables powerful interactivity with libraries like ipyleaflet, ipydatagrid, and bqplot.
---
# How can I use ipywidget library X?

Solara can work with any ipywidget library, such as [ipyleaflet](https://github.com/jupyter-widgets/ipyleaflet), [ipydatagrid](https://github.com/bloomberg/ipydatagrid) or [bqplot](https://github.com/bqplot/bqplot).
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
---
title: Understanding Solara's functionality
description: Solara builds on existing technologies. If you are new to Solara or some of the underlying technologies, you may feel lost at times.
These 'understanding' guides are meant to help you understand topics at a deeper level and how they connect to Solara.
---

# Introduction

Solara builds on existing technologies. If you are new to Solara or some of the underlying technologies, you may feel lost at times.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
title: Understanding how ipywidgets work together with Solara
description: Solara's primarily standalone app approach differs from the ipywidgets one. This article dives deeper into the different approaches and adapting to using
ipywidgets within Solara.
---
# IPywidgets

* [Documentation](https://ipywidgets.readthedocs.io/en/stable/)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
title: Using ipyvuetify widgets with Solara
description: Ipyvuetify is an ipywidgets based library that wraps the Vuetify javascript framework for use with python widgets. Learn how to use these to build apps with Solara.
---
# ipyvuetify

* [Documentation](https://ipyvuetify.readthedocs.io/)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
title: Understanding how Solara builds on Reacton
description: Solara adapts the React way of using components declaratively to build UIs and brings it to Python.
---
# Reacton

* [Documentation](https://reacton.solara.dev/)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
title: Understanding the basics of Reacton
description: Using your favorite component, we try to understand better how it works to improve your understanding of Reacton and, thus, how to use Solara.
---
# Reacton basic understanding


Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
title: The anatomy of Solara's functionality
description: Dive deep into how Solara uses the technologies it builds on.
---
# Anatomy

For communication, it is useful to speak the same language and use the same idiom.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
title: The rules of hooks in Solara
description: Learn the rules that govern the usage of hooks in your Solara application.
----
# Rules of hooks

For now, we refer to the [ReactJS documentation](https://reactjs.org/docs/hooks-rules.html).
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
---
title: Using Solara with containers to build complex UIs
description: Solara allows for using python with statements to populate your UIs in a structured manner. This makes it easy to compose different components to build cohesive
wholes.
---

# Laying out components with containers

## Introduction
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
title: Understanding different parts of Solara
description: Solara is made of two main components, the bulk of the Solara package with UI elements that can be used together with Jupyter, and Solara server, which
allows for these UI elements to be used in standalone apps and dashboards
---
# Solara

Solara combines [ipywidgets](./ipywidgets), [reacton](./reacton) and puts it into a opinionated framework to make web apps with a focus on data (data apps for short).
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
title: Understanding routing in multi-page solara apps
description: Dive into Solara's routing, which provides a powerful way to compose multiple pages or dashboards into an integrated app.
---
# Routing

Routing takes care of linking a web address (more specifically the [pathname](https://developer.mozilla.org/en-US/docs/Web/API/Location), e.g. "/docs/basics/solara") to a state of the UI,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
title: Understanding the way Solara server works
description: Solara server enables running ipywidgets-based applications as standalone dashboards and apps, allowing multiple "Virtual kernels" to share
the same process for better performance and scalability.
---
# Solara server

The solara server enables running ipywidgets based applications without a real Jupyter kernel, allowing multiple "Virtual kernels" to share the same process for better performance and scalability.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
title: Working together with Voilà
description: Voilà, together with `voila-vuetify` is an alternative to Solara server. The most significant difference is that Voilà will start one kernel/process
per page request, while Solara server is more scalable.
---
# Voilà

[Voilà](https://voila.readthedocs.io/) allows you to convert a Jupyter Notebook into an interactive dashboard that allows you to share your work with others.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
title: Using OAuth in your Solara app
description: Open Authorization can be readily integrated into your Solara applications via the Solara-Enterprise package.
---
# OAuth: authentication and authorization support

## What is OAuth
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
title: Contributing to Solara
description: You do not need to be a developer to contribute to Solara. We welcome all contributions, bug reports, documentation improvements and code contributions.
---
# Contributing to Solara

You do not need to be a developer to contribute to Solara. We welcome all contributions, bug reports, documentation improvements and code contributions.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
title: Development setup for Solara
description: Learn how to set up your installation for developing on the Solara itself.
---
# Development

See also [the contributing guide](/documentation/advanced/development/contribute) for more information on how to contribute to Solara.
Expand Down
Empty file.
3 changes: 2 additions & 1 deletion solara/website/pages/documentation/faq/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from pathlib import Path

import solara
from solara.website.components.markdown import MarkdownWithMetadata

title = "FAQ"
HERE = Path(__file__)


@solara.component
def Page(route_external=None):
solara.Markdown(Path(HERE.parent / "content" / "99-faq.md").read_text())
MarkdownWithMetadata(Path(HERE.parent / "content" / "99-faq.md").read_text())
5 changes: 4 additions & 1 deletion solara/website/pages/documentation/faq/content/99-faq.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@

---
title: FAQ about Solara
description: Answers to some common questions about using Solara, and building your app using the framework
---
# FAQ

## I am not interested in the server, I'm happy with Jupyter/Voila, what's in it for me?
Expand Down
10 changes: 2 additions & 8 deletions solara/website/pages/documentation/getting_started/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
from pathlib import Path

import solara
from solara.autorouting import generate_routes_directory
from solara.website.components.markdown import MarkdownWithMetadata

title = "Getting Started"
HERE = Path(__file__)
# if we didn't put the content in the subdirectory, but pointed to the current file
# we would include the current file recursively, causing an infinite loop
routes = generate_routes_directory(HERE.parent / "content")


@solara.component
def Page(route_external=None):
solara.Markdown(Path(HERE.parent / "content" / "01-introduction.md").read_text())
routes = generate_routes_directory(HERE.parent / "content", MarkdownWithMetadata)
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
title: Solara Quickstart
description: Get started with building web- and data-apps in pure python with Solara.
---

# Quickstart

This 1-minute quickstart will get you to:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
title: A quick introduction to Solara
description: Solara is an Open Source library that lets you use and build data-focused web apps (data apps) using reusable UI components. Here you'll learn the basics!
---
# Introduction


Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
title: Installing Solara
description: Installation should be as easy as running pip install Solara. Read on for advanced setups.
---
# Installation

## Create a virtual environment
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
title: Solara Tutorials
description: A collection of tutorials for those learning to use Solara, each geared towards a users coming from particular backgrounds, such as data science, or
users coming from other frameworks like Streamlit.
---
# Tutorials

Instead of having one tutorial, we have tutorials for different audiences.
Expand Down
Loading
Loading