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

Feature request: non react API to toggle site color theme #8672

Closed
1 of 2 tasks
antonk52 opened this issue Feb 16, 2023 · 8 comments · Fixed by #8708
Closed
1 of 2 tasks

Feature request: non react API to toggle site color theme #8672

antonk52 opened this issue Feb 16, 2023 · 8 comments · Fixed by #8708
Labels
feature This is not a bug or issue with Docusausus, per se. It is a feature request for the future.

Comments

@antonk52
Copy link
Contributor

Have you read the Contributing Guidelines on issues?

Description

Currently in Docusaurus theme toggler is used to switch between light and dark theme. There is an exposed API with react context from contexts/colorMode.tsx. Due to the exposed API being a react context provider and a react hook this limits the usage to the code within the react application. If we look into what is needed to toggle the theme, it is essentially is setting html data attribute here and storing it in local storage here.

I would like to propose to expose this API as a regular function that can be used outside of the react application.

Has this been requested on Canny?

No response

Motivation

Internally at Meta we use docusaurus for internal and external documentation. Some pages can be embedded via an iframe on other internal non docusaurus sites or electron applications. Due to the default docusaurus theme being light, the background color is not set. This way when the iframe host is in a dark theme the iframed docusaurus site has a dark background while the text content is also dark color and it becomes unreadable. I'm currently working around it by providing the parent's theme as an url query param and manually setting html data attribute to appropriate theme in the docusaurus sites.

Since the embedded pages can also be custom docusaurus pages (src/pages/*). They can have a custom layout and swizzling a builtin docusaurus component to inject code that would interact with color context won't work.

API design

No response

Have you tried building it?

No response

Self-service

  • I'd be willing to contribute this feature to Docusaurus myself.
@antonk52 antonk52 added feature This is not a bug or issue with Docusausus, per se. It is a feature request for the future. status: needs triage This issue has not been triaged by maintainers labels Feb 16, 2023
@slorber
Copy link
Collaborator

slorber commented Feb 16, 2023

I would like to propose to expose this API as a regular function that can be used outside of the react application.

What would this API look like? Do you import it or is it global?

When/how would you call such a function? It would probably have to be called asap if you want to avoid a theme flash (unwanted light=>dark transition).

Note that setting the localStorage/html attribute value is maybe not enough: you also have to ensure the React state value is up to date. If you set your localStorage/html attribute before React hydration, it should initialize properly using that value. If you set localStorage with a delay after hydration, then the React state will be stale.

Due to the default docusaurus theme being light, the background color is not set. This way when the iframe host is in a dark theme the iframed docusaurus site has a dark background while the text content is also dark color and it becomes unreadable.

I have a hard time understanding what you mean here 😅

I'm currently working around it by providing the parent's theme as an url query param and manually setting html data attribute to appropriate theme in the docusaurus sites.

That looks appropriate to me. The host doesn't have many ways to communicate with the iframe (at least in browsers, because in WebView/Electron/RN you can more easily inject scripts). A querystring param is a good way to communicate something to the child iframe.

Since the embedded pages can also be custom docusaurus pages (src/pages/*). They can have a custom layout and swizzling a builtin docusaurus component to inject code that would interact with color context won't work.

Your custom layouts could declare a ColorModeProvider, like the default theme layout do. It's not considered a public API surface but is quite stable/safe to use.

@slorber slorber removed the status: needs triage This issue has not been triaged by maintainers label Feb 16, 2023
@antonk52
Copy link
Contributor Author

What would this API look like? Do you import it or is it global?

I think a synchronous function that can be imported from docusaurus internals is a sensible API for this case.

When/how would you call such a function?

Currently we are setting a website theme in a file that is added via getClientModules()

I have a hard time understanding what you mean here

I was able to repro this in the local build of docusaurus website. Everything inside a red border is an iframe to a different page. In browser devtools I had to change the theme for the page in the iframe to light and disable the background color to reproduce the issue.

Screenshot 2023-02-21 at 11 19 03

Your custom layouts could declare a ColorModeProvider, like the default theme layout do. It's not considered a public API surface but is quite stable/safe to use.

This is true, the motivation behind this proposal was to be able to do this without the maintainers of the embedded website to do any extra work. Currently it is possible due to most websites using the same docusaurus preset. In this preset we check the query param and set the theme accordingly.

@slorber
Copy link
Collaborator

slorber commented Feb 24, 2023

@antonk52 I'm still not sure to understand what you mean by

Due to the default docusaurus theme being light, the background color is not set.

In browser devtools I had to change the theme for the page in the iframe to light and disable the background color to reproduce the issue.

When the Docusaurus theme is light, as far as I know we define a background color. I don't understand how/why you disable it, and what I'm supposed to see in the screenshot here because of course not having a background iframe color will lead to this issue 😅 It's like if you complained that the text is red just after adding color: red; to it 😄


Was wondering if it's really needed to have such an imperative API.

What if we had a first-class querystring to control the initial displayed theme of a Docusaurus website? That looks more convenient to use and other users might find it useful too.

I did a poc here: #8708

https://deploy-preview-8708--docusaurus-2.netlify.app/tests/pages/embeds

CleanShot 2023-02-24 at 17 00 30@2x

CleanShot 2023-02-24 at 17 07 22@2x

In the demo above, make sure to play with the parent/host and iframe theme toggles to see how things behave. The querystring is only used for the initial theme and to override the localStorage value, but whenever the localStorage value is changed, all the iframes and parent will resync to the localStorage value.

CleanShot 2023-02-24 at 17 08 17@2x

In practice this shouldn't behave exactly like that in your case because here I'm embedding the app inside itself so they share the same localStorage space 🤪

Note: if your parent/host has a theme toggle, you could reload the iframe thanks to React keys, using the new theme querystring param. We could eventually optimize that later but a full iframe remount doesn't seem like a big deal.

My suggestion: try to embed this deploy preview (https://deploy-preview-8708--docusaurus-2.netlify.app/) in your Docusaurus/Electron/other internal app using the querystring, and tell me if it works like you'd like it to.

@antonk52
Copy link
Contributor Author

When the Docusaurus theme is light, as far as I know we define a background color. I don't understand how/why you disable it, and what I'm supposed to see in the screenshot here because of course not having a background iframe color will lead to this issue 😅 It's like if you complained that the text is red just after adding color: red; to it 😄

You're 100% correct as it seems to be a bug on our side. I can reproduce this bug with flipper website though haven't found the source for it. Having said that, it would be nice to have a way to control website's theme externally for a more consistent experience.

What if we had a first-class querystring to control the initial displayed theme of a Docusaurus website? That looks more convenient to use and other users might find it useful too.

A first class query string sounds like a perfect solution and suits our needs well. We'd be happy with either of these solutions.

they share the same localStorage space 🤪

I came across this during reproducing the issue on the docusaurus site. This is why I explicitly specified that I had to hardcode the theme via devtools.

My suggestion: try to embed this deploy preview (https://deploy-preview-8708--docusaurus-2.netlify.app/) in your Docusaurus/Electron/other internal app using the querystring, and tell me if it works like you'd like it to.

Just tested and works like charm 👍

@slorber
Copy link
Collaborator

slorber commented Mar 2, 2023

Thanks for the feedback @antonk52

Do you think the current PR is good enough? Is docusaurus-theme an appropriate query-string name?

Was wondering how do you embed the site currently, do you have any screenshot to share? In particular I'm interested to know how do you eventually prevent the navigation on the iframe, or hide some unnecessary layout elements for embedded docs?

Asking because it's related to #7480

I was wondering if an extra way to easily set a custom class on the iframe document wouldn't be convenient too?

?docusaurus-theme=dark&docusaurus-html-class=embedded-iframe

This could allow you to easily hide unwanted layout elements with CSS when a doc is embedded, without FOUC.

html.embedded-iframe nav.navbar {
  display: none;
}

Does it make sense?

@antonk52
Copy link
Contributor Author

antonk52 commented Mar 2, 2023

Do you think the current PR is good enough?

I've checked #7480 and it looks great!

Is docusaurus-theme an appropriate query-string name?

This works for our case and should not collide with any other existing query params. I like that it includes docusaurus in the name.

Was wondering how do you embed the site currently, do you have any screenshot to share?

Here is what it looks like currently. Everything in the middle in between the sidebase and below the overview & setup tabs is the iframe.

333120104_1359907384804006_8075185698939488583_n

Here is an example of the of the page that get's embedded flipper crash-reported plugin overview and here is the source for it in OSS flipper codebase.

In particular I'm interested to know how do you eventually prevent the navigation on the iframe, or hide some unnecessary layout elements for embedded docs?

When you run yarn build in flipper/website it symlinks this file as flipper/website/src/embedded-pages. The embedded pages are using a custom layout defined here and it is used via docusaurus-content-pages plugin here. The custom layout is used to remove all of the unnecessary items like sidebar/header/footer.

Unfortunately the place where it is being embedded inside the flipper electron app is not OSS so I can not share a link for it. Though, it is a plain <iframe src={url} {/* other props */} />.

I was wondering if an extra way to easily set a custom class on the iframe document wouldn't be convenient too?

I see how both features use query params to communicate with the frame on what and how they want to be displayed. But this sounds like a separate feature to me.

Hope this provided information helps

@slorber
Copy link
Collaborator

slorber commented Mar 2, 2023

Thanks, I understand better now: somehow you found a way to build the same source docs in 2 distinct variants, a good workaround until we implement a variant system (#7480)

Will merge the PR soon, and see if someone can come up with a need for the html class name, also presented the idea here: #7480 (comment)

@slorber
Copy link
Collaborator

slorber commented May 31, 2023

FYI in #9028 we implement the ability to inject custom data attributes to the root html element. (injecting a class was more complicated and probably solves the same usecase anyway)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature This is not a bug or issue with Docusausus, per se. It is a feature request for the future.
Projects
None yet
2 participants