Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 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
12 changes: 6 additions & 6 deletions shiny/ui/_include_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ def include_js(
method
One of the following:

* ``"link"`` is the link to the CSS file via a :func:`~shiny.ui.tags.link` tag. This
* ``"link"`` is the link to the JS file via a :func:`~shiny.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
* ``"link_files"`` is the same as ``"link"``, but also allow for the JS 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``
Expand All @@ -48,7 +48,7 @@ def include_js(
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
* ``"inline"`` is the inline the JS file contents within a
:func:`~shiny.ui.tags.style` tag.
**kwargs
Attributes which are passed on to `~shiny.ui.tags.script`.
Expand Down Expand Up @@ -234,17 +234,17 @@ def maybe_copy_files(path: Path | str, include_files: bool) -> tuple[str, str]:
else:
os.makedirs(tmpdir, exist_ok=True)
shutil.copy(path, path_dest)

return path_dest, hash


def get_hash(path: Path | str, include_files: bool) -> str:
if include_files:
key = get_file_key(path)
else:
dir = os.path.dirname(path)
files = glob.iglob(os.path.join(dir, "**"), recursive=True)
key = "\n".join([get_file_key(x) for x in files])
else:
key = get_file_key(path)

return hash_deterministic(key)


Expand Down
38 changes: 38 additions & 0 deletions tests/playwright/shiny/bugs/2061-css-js-inclusion/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from pathlib import Path

from shiny import App, Inputs, Outputs, Session, ui

custom_css = ui.include_css(
Path(__file__).parent / "css" / "style.css",
method="link_files",
)

custom_js = ui.include_js(
Path(__file__).parent / "js" / "customjs.js",
method="link_files",
)

# path where the JS file's parent directory is mounted
href = custom_js.get_dependencies()[0].source_path_map()["href"]

# Define the UI
app_ui = ui.page_fluid(
custom_css,
custom_js,
ui.tags.script(src=href + "/customjs2.js"),
ui.h1("Simple Shiny App with External CSS"),
ui.div(
ui.p("This is a simple Shiny app that demonstrates ui.include_css()"),
ui.p("The styling comes from an external CSS file!"),
class_="content",
),
)


# Define the server
def server(input: Inputs, output: Outputs, session: Session):
pass


# Create and run the app
app = App(app_ui, server)
17 changes: 17 additions & 0 deletions tests/playwright/shiny/bugs/2061-css-js-inclusion/css/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
body {
font-family: Arial, sans-serif;
}

h1 {
color: black;
border-bottom: 2px solid #4682b4;
padding-bottom: 10px;
}

.content {
margin: 20px;
padding: 15px;
background-color: white;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const newParagraph = document.createElement('p');
newParagraph.textContent = 'Heyo!';
document.body.appendChild(newParagraph);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const special = document.createElement('p');
special.textContent = 'Also here!';
document.body.appendChild(special);
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from playwright.sync_api import Page, expect

from shiny.run import ShinyAppProc


def test_inclusion(page: Page, local_app: ShinyAppProc) -> None:
page.goto(local_app.url)

expect(page.locator("body > p").first).to_have_text("Heyo!")
expect(page.locator("body > p").last).to_have_text("Also here!")
Loading