From 3bc7117380ff9bb9eed41dc14001ed92862ebc50 Mon Sep 17 00:00:00 2001 From: Garrick Aden-Buie Date: Mon, 18 Dec 2023 12:01:39 -0500 Subject: [PATCH] docs: Use definition lists for parameter descriptions to enable full markdown support (#901) --- docs/.gitignore | 1 + docs/Makefile | 2 +- docs/_quarto.yml | 1 + docs/_quartodoc.yml | 2 ++ docs/_renderer.py | 16 +++++----- docs/shiny-docs.css | 4 +++ setup.cfg | 4 +-- shiny/express/layout.py | 52 +++++++++++++++++++------------- shiny/ui/_include_helpers.py | 58 ++++++++++++++++++++---------------- shiny/ui/_layout.py | 27 ++++++++++------- shiny/ui/_sidebar.py | 40 +++++++++++++++---------- shiny/ui/_valuebox.py | 24 ++++++++------- 12 files changed, 136 insertions(+), 95 deletions(-) create mode 100644 docs/shiny-docs.css diff --git a/docs/.gitignore b/docs/.gitignore index 95eb9c701..a3135790a 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -4,3 +4,4 @@ _inv/ _sidebar.yml /.quarto/ objects.json +site_libs/ diff --git a/docs/Makefile b/docs/Makefile index 026aa511f..91fabe65c 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -46,7 +46,7 @@ deps: $(PYBIN) ## Install build dependencies $(PYBIN)/pip install pip --upgrade $(PYBIN)/pip install -e ..[doc] -quartodoc: ## Build qmd files for API docs +quartodoc: $(PYBIN) ## Build qmd files for API docs . $(PYBIN)/activate \ && quartodoc interlinks \ && quartodoc build --config _quartodoc.yml --verbose diff --git a/docs/_quarto.yml b/docs/_quarto.yml index b4f5d299c..3e1093ae7 100644 --- a/docs/_quarto.yml +++ b/docs/_quarto.yml @@ -5,6 +5,7 @@ project: format: html: toc: true + css: shiny-docs.css website: title: "Shiny for Python (dev version)" diff --git a/docs/_quartodoc.yml b/docs/_quartodoc.yml index 08b9279af..9be9d456d 100644 --- a/docs/_quartodoc.yml +++ b/docs/_quartodoc.yml @@ -18,6 +18,7 @@ quartodoc: - express.layout.span - express.layout.pre - express.layout.sidebar + - express.layout.layout_columns - express.layout.layout_column_wrap - express.layout.column - express.layout.row @@ -46,6 +47,7 @@ quartodoc: contents: - ui.sidebar - ui.layout_sidebar + - ui.layout_columns - ui.layout_column_wrap - ui.card - ui.card_header diff --git a/docs/_renderer.py b/docs/_renderer.py index 7020ec69b..fc4ccac56 100644 --- a/docs/_renderer.py +++ b/docs/_renderer.py @@ -13,6 +13,7 @@ from griffe.docstrings import dataclasses as ds from plum import dispatch from quartodoc import MdRenderer +from quartodoc.pandoc.blocks import DefinitionList from quartodoc.renderers.base import convert_rst_link_to_md, sanitize SHINY_PATH = Path(files("shiny").joinpath()) @@ -128,17 +129,17 @@ def render_annotation(self, el: None): return "" @dispatch - def render_annotation(self, el: exp.Expression): - # an expression is essentially a list[exp.Name | str] + def render_annotation(self, el: exp.Expr): + # an expression is essentially a list[exp.ExprName | str] # e.g. Optional[TagList] # -> [Name(source="Optional", ...), "[", Name(...), "]"] return "".join(map(self.render_annotation, el)) @dispatch - def render_annotation(self, el: exp.Name): + def render_annotation(self, el: exp.ExprName): # e.g. Name(source="Optional", full="typing.Optional") - return f"[{el.source}](`{el.full}`)" + return f"[{el.name}](`{el.canonical_path}`)" @dispatch def summarize(self, el: dc.Object | dc.Alias): @@ -158,15 +159,14 @@ def render(self, el: ds.DocstringParameter): # Wrap everything in a code block to allow for links param = "" + param + "" - clean_desc = sanitize(el.description, allow_markdown=True) - return (param, clean_desc) + return (param, el.description) @dispatch def render(self, el: ds.DocstringSectionParameters): rows = list(map(self.render, el.value)) - header = ["Parameter", "Description"] + # rows is a list of tuples of (, ) - return self._render_table(rows, header) + return str(DefinitionList(rows)) @dispatch def signature(self, el: dc.Function, source: Optional[dc.Alias] = None): diff --git a/docs/shiny-docs.css b/docs/shiny-docs.css new file mode 100644 index 000000000..f5b1c0ba3 --- /dev/null +++ b/docs/shiny-docs.css @@ -0,0 +1,4 @@ +#parameters dd { + margin-top: 0.5rem; + margin-left: 2rem; +} diff --git a/setup.cfg b/setup.cfg index ba7d24196..6322b6094 100644 --- a/setup.cfg +++ b/setup.cfg @@ -103,8 +103,8 @@ doc = tabulate shinylive==0.1.1 pydantic==1.10 - quartodoc==0.4.1 - griffe==0.32.3 + quartodoc==0.7.2 + griffe==0.33.0 [options.packages.find] include = shiny, shiny.* diff --git a/shiny/express/layout.py b/shiny/express/layout.py index 8c78d8ef0..e97089f79 100644 --- a/shiny/express/layout.py +++ b/shiny/express/layout.py @@ -82,10 +82,12 @@ def sidebar( position Where the sidebar should appear relative to the main content. open - The initial state of the sidebar. It can be `"desktop"` (the sidebar starts open - on desktop screen, closed on mobile), `"open"` or `True` (the sidebar starts - open), `"closed"` or `False` (the sidebar starts closed), or `"always"` or - `None` (the sidebar is always open and cannot be closed). + The initial state of the sidebar. + + * `"desktop"`: the sidebar starts open on desktop screen, closed on mobile + * `"open"` or `True`: the sidebar starts open + * `"closed"` or `False`: the sidebar starts closed + * `"always"` or `None`: the sidebar is always open and cannot be closed In :func:`~shiny.ui.update_sidebar`, `open` indicates the desired state of the sidebar. Note that :func:`~shiny.ui.update_sidebar` can only open or close the @@ -114,12 +116,15 @@ def sidebar( padding Padding within the sidebar itself. This can be a numeric vector (which will be interpreted as pixels) or a character vector with valid CSS lengths. `padding` - may be one to four values. If one, then that value will be used for all four - sides. If two, then the first value will be used for the top and bottom, while - the second value will be used for left and right. If three, then the first will - be used for top, the second will be left and right, and the third will be - bottom. If four, then the values will be interpreted as top, right, bottom, and - left respectively. + may be one to four values. + + * If a single value, then that value will be used for all four sides. + * If two, then the first value will be used for the top and bottom, while + the second value will be used for left and right. + * If three values, then the first will be used for top, the second will be left + and right, and the third will be bottom. + * If four, then the values will be interpreted as top, right, bottom, and left + respectively. Returns ------- @@ -168,21 +173,26 @@ def layout_column_wrap( Parameters ---------- width - The desired width of each card. It can be a (unit-less) number between 0 and 1 - and should be specified as `1/num`, where `num` represents the number of desired - columns. It can be a CSS length unit representing either the minimum (when - `fixed_width=False`) or fixed width (`fixed_width=True`). It can also be `None`, - which allows power users to set the `grid-template-columns` CSS property - manually, either via a `style` attribute or a CSS stylesheet. If missing, a - value of `200px` will be used. + The desired width of each card. It can be one of the following: + + * A (unit-less) number between 0 and 1, specified as `1/num`, where `num` + represents the number of desired columns. + * A CSS length unit representing either the minimum (when `fixed_width=False`) + or fixed width (`fixed_width=True`). + * `None`, which allows power users to set the `grid-template-columns` CSS + property manually, either via a `style` attribute or a CSS stylesheet. + * If missing, a value of `200px` will be used. fixed_width When `width` is greater than 1 or is a CSS length unit, e.g. `"200px"`, `fixed_width` indicates whether that `width` value represents the absolute size of each column (`fixed_width=TRUE`) or the minimum size of a column - (`fixed_width=FALSE`). When `fixed_width=FALSE`, new columns are added to a row - when `width` space is available and columns will never exceed the container or - viewport size. When `fixed_width=TRUE`, all columns will be exactly `width` - wide, which may result in columns overflowing the parent container. + (`fixed_width=FALSE`). + + When `fixed_width=FALSE`, new columns are added to a row when `width` space is + available and columns will never exceed the container or viewport size. + + When `fixed_width=TRUE`, all columns will be exactly `width` wide, which may + result in columns overflowing the parent container. heights_equal If `"all"` (the default), every card in every row of the grid will have the same height. If `"row"`, then every card in _each_ row of the grid will have the same diff --git a/shiny/ui/_include_helpers.py b/shiny/ui/_include_helpers.py index 1739bfc40..88c339bb5 100644 --- a/shiny/ui/_include_helpers.py +++ b/shiny/ui/_include_helpers.py @@ -34,19 +34,22 @@ def include_js( path A path to a JS file. method - One of the following: ``"link"``, ``"link_files"``, or ``"inline"``. ``"link"`` - is the link to the CSS file via a :func:`~ui.tags.link` tag. This method is - generally preferrable to ``"inline"`` since it allows the browser to cache the - file. ``"link_files"`` is the same as ``"link"``, but also allow for the CSS - file to request other files within ``path``'s immediate parent directory (e.g., - ``@import()`` another file). Note that this isn't the default behavior because - you should **be careful not to include files in the same directory as ``path`` - that contain sensitive information**. A good general rule of thumb to follow is - to have ``path`` be located in a subdirectory of the app directory. For example, - if the app's source is located at ``/app/app.py``, then ``path`` should be - somewhere like ``/app/css/custom.css`` (and all the other relevant accompanying - 'safe' files should be located under ``/app/css/``). And finally, ``"inline"`` - is the inline the CSS file contents within a :func:`~ui.tags.style` tag. + One of the following: + + * ``"link"`` is the link to the CSS file via a :func:`~ui.tags.link` tag. This + method is generally preferable to ``"inline"`` since it allows the browser to + cache the file. + * ``"link_files"`` is the same as ``"link"``, but also allow for the CSS file to + request other files within ``path``'s immediate parent directory (e.g., + ``@import()`` another file). Note that this isn't the default behavior because + you should **be careful not to include files in the same directory as ``path`` + that contain sensitive information**. A good general rule of thumb to follow + is to have ``path`` be located in a subdirectory of the app directory. For + example, if the app's source is located at ``/app/app.py``, then ``path`` + should be somewhere like ``/app/css/custom.css`` (and all the other relevant + accompanying 'safe' files should be located under ``/app/css/``). + * ``"inline"`` is the inline the CSS file contents within a + :func:`~ui.tags.style` tag. **kwargs Attributes which are passed on to `~ui.tags.script` @@ -105,19 +108,22 @@ def include_css( path A path to a CSS file. method - One of the following: ``"link"``, ``"link_files"``, or ``"inline"``. ``"link"`` - is the link to the CSS file via a :func:`~ui.tags.link` tag. This method is - generally preferrable to ``"inline"`` since it allows the browser to cache the - file. ``"link_files"`` is the same as ``"link"``, but also allow for the CSS - file to request other files within ``path``'s immediate parent directory (e.g., - ``@import()`` another file). Note that this isn't the default behavior because - you should **be careful not to include files in the same directory as ``path`` - that contain sensitive information**. A good general rule of thumb to follow is - to have ``path`` be located in a subdirectory of the app directory. For example, - if the app's source is located at ``/app/app.py``, then ``path`` should be - somewhere like ``/app/css/custom.css`` (and all the other relevant accompanying - 'safe' files should be located under ``/app/css/``). And finally, ``"inline"`` - is the inline the CSS file contents within a :func:`~ui.tags.style` tag. + One of the following: + + * ``"link"`` is the link to the CSS file via a :func:`~ui.tags.link` tag. This + method is generally preferable to ``"inline"`` since it allows the browser to + cache the file. + * ``"link_files"`` is the same as ``"link"``, but also allow for the CSS file to + request other files within ``path``'s immediate parent directory (e.g., + ``@import()`` another file). Note that this isn't the default behavior because + you should **be careful not to include files in the same directory as ``path`` + that contain sensitive information**. A good general rule of thumb to follow + is to have ``path`` be located in a subdirectory of the app directory. For + example, if the app's source is located at ``/app/app.py``, then ``path`` + should be somewhere like ``/app/css/custom.css`` (and all the other relevant + accompanying 'safe' files should be located under ``/app/css/``). + * ``"inline"`` is the inline the CSS file contents within a + :func:`~ui.tags.style` tag. Returns diff --git a/shiny/ui/_layout.py b/shiny/ui/_layout.py index 0ad6743a8..5223f8b04 100644 --- a/shiny/ui/_layout.py +++ b/shiny/ui/_layout.py @@ -43,21 +43,26 @@ def layout_column_wrap( :func:`~shiny.ui.card`). Named arguments become attributes on the containing :class:`~htmltools.Tag` element. width - The desired width of each card. It can be a (unit-less) number between 0 and 1 - and should be specified as `1/num`, where `num` represents the number of desired - columns. It can be a CSS length unit representing either the minimum (when - `fixed_width=False`) or fixed width (`fixed_width=True`). It can also be `None`, - which allows power users to set the `grid-template-columns` CSS property - manually, either via a `style` attribute or a CSS stylesheet. If missing, a - value of `200px` will be used. + The desired width of each card. It can be one of the following: + + * A (unit-less) number between 0 and 1, specified as `1/num`, where `num` + represents the number of desired columns. + * A CSS length unit representing either the minimum (when `fixed_width=False`) + or fixed width (`fixed_width=True`). + * `None`, which allows power users to set the `grid-template-columns` CSS + property manually, either via a `style` attribute or a CSS stylesheet. + * If missing, a value of `200px` will be used. fixed_width When `width` is greater than 1 or is a CSS length unit, e.g. `"200px"`, `fixed_width` indicates whether that `width` value represents the absolute size of each column (`fixed_width=TRUE`) or the minimum size of a column - (`fixed_width=FALSE`). When `fixed_width=FALSE`, new columns are added to a row - when `width` space is available and columns will never exceed the container or - viewport size. When `fixed_width=TRUE`, all columns will be exactly `width` - wide, which may result in columns overflowing the parent container. + (`fixed_width=FALSE`). + + When `fixed_width=FALSE`, new columns are added to a row when `width` space is + available and columns will never exceed the container or viewport size. + + When `fixed_width=TRUE`, all columns will be exactly `width` wide, which may + result in columns overflowing the parent container. heights_equal If `"all"` (the default), every card in every row of the grid will have the same height. If `"row"`, then every card in _each_ row of the grid will have the same diff --git a/shiny/ui/_sidebar.py b/shiny/ui/_sidebar.py index f5a7bd1b2..4f2af4e5d 100644 --- a/shiny/ui/_sidebar.py +++ b/shiny/ui/_sidebar.py @@ -168,10 +168,12 @@ def sidebar( position Where the sidebar should appear relative to the main content. open - The initial state of the sidebar. It can be `"desktop"` (the sidebar starts open - on desktop screen, closed on mobile), `"open"` or `True` (the sidebar starts - open), `"closed"` or `False` (the sidebar starts closed), or `"always"` or - `None` (the sidebar is always open and cannot be closed). + The initial state of the sidebar. + + * `"desktop"`: the sidebar starts open on desktop screen, closed on mobile + * `"open"` or `True`: the sidebar starts open + * `"closed"` or `False`: the sidebar starts closed + * `"always"` or `None`: the sidebar is always open and cannot be closed In :func:`~shiny.ui.update_sidebar`, `open` indicates the desired state of the sidebar. Note that :func:`~shiny.ui.update_sidebar` can only open or close the @@ -200,12 +202,15 @@ def sidebar( padding Padding within the sidebar itself. This can be a numeric vector (which will be interpreted as pixels) or a character vector with valid CSS lengths. `padding` - may be one to four values. If one, then that value will be used for all four - sides. If two, then the first value will be used for the top and bottom, while - the second value will be used for left and right. If three, then the first will - be used for top, the second will be left and right, and the third will be - bottom. If four, then the values will be interpreted as top, right, bottom, and - left respectively. + may be one to four values. + + * If a single value, then that value will be used for all four sides. + * If two, then the first value will be used for the top and bottom, while + the second value will be used for left and right. + * If three values, then the first will be used for top, the second will be left + and right, and the third will be bottom. + * If four, then the values will be interpreted as top, right, bottom, and left + respectively. Returns ------- @@ -337,12 +342,15 @@ def layout_sidebar( padding Padding within the sidebar itself. This can be a numeric vector (which will be interpreted as pixels) or a character vector with valid CSS lengths. `padding` - may be one to four values. If one, then that value will be used for all four - sides. If two, then the first value will be used for the top and bottom, while - the second value will be used for left and right. If three, then the first will - be used for top, the second will be left and right, and the third will be - bottom. If four, then the values will be interpreted as top, right, bottom, and - left respectively. + may be one to four values. + + * If a single value, then that value will be used for all four sides. + * If two, then the first value will be used for the top and bottom, while + the second value will be used for left and right. + * If three values, then the first will be used for top, the second will be left + and right, and the third will be bottom. + * If four, then the values will be interpreted as top, right, bottom, and left + respectively. height Any valid CSS unit to use for the height. diff --git a/shiny/ui/_valuebox.py b/shiny/ui/_valuebox.py index cdace35f1..ed9738768 100644 --- a/shiny/ui/_valuebox.py +++ b/shiny/ui/_valuebox.py @@ -337,16 +337,20 @@ def value_box( theme The name of a theme (e.g. `"primary"`, `"danger"`, `"purple"`, `"bg-green"`, `"text-red"`) for the value box, or a theme constructed with - :func:`~shiny.ui.value_box_theme`. The theme names provide a convenient way to - use your app's Bootstrap theme colors as the foreground or background colors of - the value box. For more control, you can create your own theme with - :func:`~shiny.ui.value_box_theme` where you can pass foreground and background - colors directly. Bootstrap supported color themes: `"blue"`, `"purple"`, - `"pink"`, `"red"`, `"orange"`, `"yellow"`, `"green"`, `"teal"`, and `"cyan"`. - These colors can be used with `bg-NAME`, `text-NAME`, and - `bg-gradient-NAME1-NAME2` to change the background, foreground, or use a - background gradient respectively. If a `theme` string does not start with - `text-` or `bg-`, it will be auto prefixed with `bg-`. + :func:`~shiny.ui.value_box_theme`. + + The theme names provide a convenient way to use your app's Bootstrap theme + colors as the foreground or background colors of the value box. For more + control, you can create your own theme with :func:`~shiny.ui.value_box_theme` + where you can pass foreground and background colors directly. + + Bootstrap supported color themes: `"blue"`, `"purple"`, `"pink"`, `"red"`, + `"orange"`, `"yellow"`, `"green"`, `"teal"`, and `"cyan"`. These colors can be + used with `bg-NAME`, `text-NAME`, and `bg-gradient-NAME1-NAME2` to change the + background, foreground, or use a background gradient respectively. + + If a `theme` string does not start with `text-` or `bg-`, it will be auto + prefixed with `bg-`. full_screen If `True`, an icon will appear when hovering over the card body. Clicking the icon expands the card to fit viewport size.