Skip to content
Open
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
30 changes: 20 additions & 10 deletions components/blocks/cloud.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useRef } from "react";
import React, { useEffect, useRef, useState } from "react";
import classNames from "classnames";

// Arguments:
Expand Down Expand Up @@ -34,6 +34,19 @@ import classNames from "classnames";
// -> https://foo.streamlit.app/bar/?embed=true&embed_options=show_padding&embed_options=show_colored_line
//
const Cloud = ({ name, path, query, height, domain, stylePlaceholder }) => {
// State to track theme, starts with light theme for SSR
const [themeEmbedOption, setThemeEmbedOption] = useState(
"embed_options=light_theme",
);

// Update theme after component mounts (client-side only)
useEffect(() => {
const currentTheme = document.documentElement.classList.contains("dark")
? "embed_options=dark_theme"
: "embed_options=light_theme";
setThemeEmbedOption(currentTheme);
}, []);

if (!domain) domain = `${name}.streamlit.app`;
if (domain.endsWith("/")) domain = domain.slice(0, -1);

Expand All @@ -44,30 +57,27 @@ const Cloud = ({ name, path, query, height, domain, stylePlaceholder }) => {
path = "";
}

let normalQueryStr = "";
let embedQueryStr = "";

// Separate "normal" query params from "embed-related" query params.
// This way we can include only the "normal" query params in the Fullscreen link.
// Note that this only applies to iframes rendered via the <Cloud> component
// in React. For iframes rendered via the ".. output::" directive we **always**
// include any provided query param in the Fullscreen link.
if (query) {
const embedQueryParams = [];
const normalQueryParams = [];
const embedQueryParams = [themeEmbedOption];
const normalQueryParams = [];

if (query) {
query.split("&").forEach((qStr) => {
if (qStr.startsWith("embed=") || qStr.startsWith("embed_options=")) {
embedQueryParams.push(qStr);
} else {
normalQueryParams.push(qStr);
}
});

embedQueryStr = "&" + embedQueryParams.join("&");
normalQueryStr = "&" + normalQueryParams.join("&");
}

const embedQueryStr = "&" + embedQueryParams.join("&");
const normalQueryStr = "&" + normalQueryParams.join("&");

if (!height) height = "10rem";

const style = stylePlaceholder
Expand Down
27 changes: 27 additions & 0 deletions components/utilities/themeToggle.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,33 @@ const ThemeToggle = () => {
document.documentElement.classList.remove(inactiveTheme);
setActiveTheme(theme);
localStorage.setItem("theme", theme);

// Force reload all Cloud iframes on the current page
const iframes = document.querySelectorAll('iframe[src*="streamlit.app"]');
iframes.forEach((iframe) => {
const currentSrc = iframe.src;
const url = new URL(currentSrc);

// Get all existing embed_options
const existingEmbedOptions = url.searchParams.getAll("embed_options");

// Remove only theme-related embed_options (light_theme or dark_theme)
const nonThemeOptions = existingEmbedOptions.filter(
(option) => option !== "light_theme" && option !== "dark_theme",
);

// Clear all embed_options and re-add the non-theme ones
url.searchParams.delete("embed_options");
nonThemeOptions.forEach((option) =>
url.searchParams.append("embed_options", option),
);

// Add new theme parameter
url.searchParams.append("embed_options", `${theme}_theme`);

// Force reload iframe with new theme
iframe.src = url.toString();
});
};

const showTooltip = () => {
Expand Down