Skip to content

Commit

Permalink
Merge pull request #455 from rstudio/nav-htmldeps
Browse files Browse the repository at this point in the history
  • Loading branch information
wch committed Apr 19, 2023
2 parents 6f893ab + 3f8b82c commit 7c02ee3
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 25 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Other changes

* `page_navbar` now accepts shinyswatch themes. (#455)


## [0.3.0] - 2023-04-03
Expand Down
44 changes: 31 additions & 13 deletions shiny/ui/_navs.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@

import copy
import re
from typing import Any, Optional, cast
from typing import Any, Optional, Sequence, cast

from htmltools import Tag, TagChild, TagList, div, tags
from htmltools import MetadataNode, Tag, TagChild, TagList, div, tags

from .._docstring import add_example
from .._namespaces import resolve_id
Expand Down Expand Up @@ -335,7 +335,7 @@ def nav_menu(


class NavSet:
args: tuple[NavSetArg]
args: tuple[NavSetArg | MetadataNode]
ul_class: str
id: Optional[str]
selected: Optional[str]
Expand All @@ -344,7 +344,7 @@ class NavSet:

def __init__(
self,
*args: NavSetArg,
*args: NavSetArg | MetadataNode,
ul_class: str,
id: Optional[str],
selected: Optional[str],
Expand Down Expand Up @@ -676,7 +676,7 @@ class NavSetPillList(NavSet):

def __init__(
self,
*args: NavSetArg,
*args: NavSetArg | MetadataNode,
ul_class: str,
id: Optional[str],
selected: Optional[str],
Expand Down Expand Up @@ -705,7 +705,7 @@ def layout(self, nav: TagChild, content: TagChild) -> Tag:


def navset_pill_list(
*args: NavSetArg,
*args: NavSetArg | MetadataNode,
id: Optional[str] = None,
selected: Optional[str] = None,
header: TagChild = None,
Expand Down Expand Up @@ -776,7 +776,7 @@ class NavSetBar(NavSet):

def __init__(
self,
*args: NavSetArg,
*args: NavSetArg | MetadataNode,
ul_class: str,
title: TagChild,
id: Optional[str],
Expand Down Expand Up @@ -853,7 +853,7 @@ def layout(self, nav: TagChild, content: TagChild) -> TagList:


def navset_bar(
*args: NavSetArg,
*args: NavSetArg | MetadataNode | Sequence[MetadataNode],
title: TagChild,
id: Optional[str] = None,
selected: Optional[str] = None,
Expand Down Expand Up @@ -922,8 +922,16 @@ def navset_bar(
See :func:`~shiny.ui.nav`.
"""

# If args contains any lists, flatten them into args.
new_args: Sequence[NavSetArg | MetadataNode] = []
for arg in args:
if isinstance(arg, (list, tuple)):
new_args.extend(arg)
else:
new_args.append(cast(NavSetArg, arg))

return NavSetBar(
*args,
*new_args,
ul_class="nav navbar-nav",
id=resolve_id(id) if id else None,
selected=selected,
Expand All @@ -942,24 +950,34 @@ def navset_bar(
# Utilities for rendering navs
# -----------------------------------------------------------------------------\
def render_navset(
*items: NavSetArg,
*items: NavSetArg | MetadataNode,
ul_class: str,
id: Optional[str],
selected: Optional[str],
context: dict[str, Any],
) -> tuple[Tag, Tag]:
tabsetid = private_random_int(1000, 10000)

# Separate MetadataNodes from NavSetArgs.
metadata_args = [x for x in items if isinstance(x, MetadataNode)]
navset_args = [x for x in items if not isinstance(x, MetadataNode)]

# If the user hasn't provided a selected value, use the first one
if selected is None:
for x in items:
for x in navset_args:
selected = x.get_value()
if selected is not None:
break

ul_tag = tags.ul(bootstrap_deps(), class_=ul_class, id=id, data_tabsetid=tabsetid)
ul_tag = tags.ul(
bootstrap_deps(),
metadata_args,
class_=ul_class,
id=id,
data_tabsetid=tabsetid,
)
div_tag = div(class_="tab-content", data_tabsetid=tabsetid)
for i, x in enumerate(items):
for i, x in enumerate(navset_args):
nav, contents = x.resolve(
selected, {**context, "tabsetid": tabsetid, "index": i}
)
Expand Down
26 changes: 14 additions & 12 deletions shiny/ui/_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@
"page_bootstrap",
)

from typing import Any, Optional
from typing import Optional, Sequence

# Tagifiable isn't used directly in this file, but it seems to necessary to import
# it somewhere for Sphinx to work cleanly.
from htmltools import Tagifiable # pyright: ignore[reportUnusedImport] # noqa: F401
from htmltools import Tag, TagChild, TagList, div, tags
from htmltools import MetadataNode, Tag, TagAttrs, TagChild, TagList, div, tags

from .._docstring import add_example
from .._namespaces import resolve_id
Expand All @@ -24,7 +21,7 @@


def page_navbar(
*args: NavSetArg,
*args: NavSetArg | MetadataNode | Sequence[MetadataNode],
title: Optional[str | Tag | TagList] = None,
id: Optional[str] = None,
selected: Optional[str] = None,
Expand All @@ -39,7 +36,7 @@ def page_navbar(
lang: Optional[str] = None,
) -> Tag:
"""
Create a navbar with a navs bar and a title.
Create a page with a navbar and a title.
Parameters
----------
Expand Down Expand Up @@ -123,7 +120,10 @@ def page_navbar(

@add_example()
def page_fluid(
*args: Any, title: Optional[str] = None, lang: Optional[str] = None, **kwargs: str
*args: TagChild | TagAttrs,
title: Optional[str] = None,
lang: Optional[str] = None,
**kwargs: str,
) -> Tag:
"""
Create a fluid page.
Expand Down Expand Up @@ -162,7 +162,10 @@ def page_fluid(

@add_example()
def page_fixed(
*args: Any, title: Optional[str] = None, lang: Optional[str] = None, **kwargs: str
*args: TagChild | TagAttrs,
title: Optional[str] = None,
lang: Optional[str] = None,
**kwargs: str,
) -> Tag:
"""
Create a fixed page.
Expand Down Expand Up @@ -201,7 +204,7 @@ def page_fixed(

# TODO: implement theme (just Bootswatch for now?)
def page_bootstrap(
*args: Any, title: Optional[str] = None, lang: Optional[str] = None
*args: TagChild | TagAttrs, title: Optional[str] = None, lang: Optional[str] = None
) -> Tag:
"""
Create a Bootstrap UI page container.
Expand Down Expand Up @@ -230,6 +233,5 @@ def page_bootstrap(
:func:`~shiny.ui.page_navbar`
"""

page = TagList(*bootstrap_deps(), *args)
head = tags.title(title) if title else None
return tags.html(tags.head(head), tags.body(page), lang=lang)
return tags.html(tags.head(head), tags.body(*bootstrap_deps(), *args), lang=lang)

0 comments on commit 7c02ee3

Please sign in to comment.