facebook / docusaurus

Easy to maintain open source documentation websites.
https://docusaurus.io
MIT License
56.34k stars 8.46k forks source link

Reset to OS theme / colorMode should possible #8074

Open juliusmarminge opened 2 years ago

juliusmarminge commented 2 years ago

Have you read the Contributing Guidelines on issues?

Prerequisites

Description

I don't think this is a bug as much as intended behavior, but I think that intention can be confusing so I'll post an issue anyways.

Docusaurus is currently handling themes both using local storage, and syncing the user preferences. This often leads to the theme going out of sync:

https://github.com/facebook/docusaurus/blob/cba8be01a3ae058a328004ba281d28c47ac0a25c/packages/docusaurus-theme-classic/src/index.ts#L42-L52

Reproducible demo

https://preferred-theme-test.vercel.app

Steps to reproduce

Lets say at day I toggle the theme on the website to use light mode. That would store a KV-pair { "theme": "light" } in localstorage. I leave the page and when I come back at night my device is now using darkmode, so I'd probably want the page to load in dark mode. However, since the KV-pair is in localstorage, that takes precedence so it loads light mode instead.

Expected behavior

I'd want the page to load in dark mode.

Actual behavior

The page loads the KV pair from localstorage and uses light mode.

Your environment

Self-service

juliusmarminge commented 2 years ago

I can submit a PR for this if you agree with my standpoint, but since I think this is intended I won't do anything until I hear back from you

Josh-Cena commented 2 years ago

The UX is quite hard to design. How should the localStorage value be deemed stale? Or should we not persist that value at all?

juliusmarminge commented 2 years ago

The UX is quite hard to design. How should the localStorage value be deemed stale? Or should we not persist that value at all?

I usually don't persist it at all tbf but there is definitely a compromise to be made.

+ If you don't use localstorage, the theme is always in sync with the user's device,

- However say the user is on dark mode but want the page in light, the theme would reset to dark on every pageload.

I'd take the payoff and assume that users who want light pages probably has light mode enabled on their device

juliusmarminge commented 2 years ago

On https://trpc.io we override this behavior by a bit hacky script implemented here https://github.com/trpc/trpc/pull/2664/files#diff-153fbbe997755581673d0a5178895a70051650f2ed919e23186dbea31b7602ef

Josh-Cena commented 2 years ago

I think refreshing definitely should not change the color mode—that would feel really shaky. The only question is whether we can invalidate the localStorage somehow in the following case:

  1. Light mode is selected—either as default or as user choice
  2. User's device switched from light mode to dark mode the next time the site is opened

I think to do that we have to persist the current system theme in local storage as well?

(Also, I use system-wide dark mode, but the dark mode on some sites is just horrible that I use light mode on those instead.)

juliusmarminge commented 2 years ago

I think refreshing definitely should not change the color mode—that would feel really shaky. The only question is whether we can invalidate the localStorage somehow in the following case:

  1. Light mode is selected—either as default or as user choice
  2. User's device switched from light mode to dark mode the next time the site is opened

I think to do that we have to persist the current system theme in local storage as well?

(Also, I use system-wide dark mode, but the dark mode on some sites is just horrible that I use light mode on those instead.)

That sounds like a good idea. We could store a blob

{"theme": "light", "userPreferred": "dark"}

and check if the mediaMatch === userPreferred in some way

juliusmarminge commented 2 years ago

I could play around and file a PR if you like?

Josh-Cena commented 2 years ago

Ah, sure, feel free to!

slorber commented 2 years ago

Hey,

To me, once a user selects light mode, we persist it and the site should forever use that color. We definitively want to keep using the explicit choice of the user. If user wants to reset to OS setting, this choice must be explicit.

If the user wants to revert to the system theme, then there must be an explicit option to do so, like on many sites.

CF https://developer.mozilla.org/

CleanShot 2022-09-30 at 16 06 11@2x

The problem is that we only have 2 values in the current switch, and the user has no ability to reset to OS switch. I'm more likely willing to add a 3rd icon in our state machine to make it at least possible to revert to os theme (ie erase the localstorage value).

It's not a very conventional UX to have and I'm not sure we can find a good icon representing OS theme though 😅 maybe a mixture of both icons at the same time? Or maybe we'd want to use a dropdown like many other websites 🤷‍♂️ some people probably won't like it.


Not 100% related to this exact problem but In general I like the ideas expressed here:

What we want is more likely to give the ability to reset to "inherit"

CleanShot 2022-09-30 at 16 12 40@2x

flying-sheep commented 1 year ago

Some people won’t like any chosen UI, but this is a tri-state piece of data. Any UI that allows switching between all three states is preferable to the current one which makes one of them inaccessible. Working is better than broken, and only once things work, UX starts to become a topic.

I built this little thing a while ago btw: https://flying-sheep.github.io/react-color-scheme-switch/

slorber commented 1 year ago

I tried to solve this but this need a bit more refactoring than I thought.

We probably need 2 states now:

If we only have the effective colorMode in state, then it becomes impossible to know we are in a state of "os color mode", and thus transition to the appropriate next value.


Also, I think the transition state machine should take into account the effective color mode to decide on which value to use next.

IE:

What I want to avoid here: users on the first visit are likely all having the OS setting. When they first click on the toggle, we probably want to give them feedback. Transitioning from light (OS setting) to light (user choice) may be a weird initial feedback 🤷‍♂️

The other option is to use a dropdown instead of a toggle button.

flying-sheep commented 1 year ago

That’s exactly the UX the Python community is converging on. I didn’t have time to expand on it when I wrote my last comment, but here’s basically me saying the exact same things as you just did, https://github.com/rust-lang/this-week-in-rust/issues/2274#issuecomment-1333723860, with some example implementations.

nasso commented 1 year ago

how about keeping the same icon button, but with a third state? clicking it cycles between "light"/"dark"/"auto". when set to "auto", just store { "theme": "auto" } in localStorage.

we just need a new icon, could be just an "A" or some i18n-friendly icon like a magic wand. the icon could also just be some sort of badge on top of the 🌙/☀️ we already have, to show both the current theme and the fact that it was automatically figured out.

that would be more than enough and is better than what we have currently imho

slorber commented 1 year ago

Yes we agree we need 3 states and an icon to represent the new 3rd state.

That's not really worth pursing this discussion, but rather working on a concrete implementation based on my comments here: https://github.com/facebook/docusaurus/issues/8074#issuecomment-1342662517

nasso commented 1 year ago

I'd like to work on that!

ilg-ul commented 1 year ago

Any progress on adding an OS theme mode?

Zwyx commented 1 year ago

Hey all,

@slorber, I'd like to suggest the solution adopted by the website https://ui.shadcn.com/ (it's a UI library project being built at https://github.com/shadcn/ui):

Please play with the theme switcher, and you'll notice how the icons work:

I find this method very intuitive, practical, easy to understand. It has three states, but it only shows the two icons that everybody understands: Sun and Moon. It doesn't require to come up with an icon for the 3rd-state, which seems to be an impossible task :smile: Even the one chosen by Mozilla is questionable. And the "laptop" icon here is great in the menu, but wouldn't be great in the button, especially because it would be the first one seen by the user when navigating to the site for the first time.

I use this method now on my new projects. I have just changed the name of the third option from "System" to "Same as device" to be more friendly to non-tech people.

(Also, this website uses next-theme under the hood — we could take inspiration from how it handles states.)

Zwyx commented 1 year ago

Just wanted to revive this. I've made a demo project showing what I suggested above, and explained the implementation in this article.

image

@slorber I'd be keen to know your opinion on this way of doing it :wink:

mahozad commented 11 months ago

Disclaimer: I'm the author of the library.

Would you like to incorporate this animated theme switch? It supports system (automatic) theme as well.

Demo 1: https://mahozad.ir/theme-switch/ Demo 2: https://mahozad.ir/android-pie-chart/

It probably addresses the following related issues too: