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

feat: add dark mode #2322

Merged
merged 14 commits into from
Feb 26, 2025
Merged

feat: add dark mode #2322

merged 14 commits into from
Feb 26, 2025

Conversation

kaf-lamed-beyt
Copy link
Contributor

fixes #1702

Hi @lidel, This is what I have so far. I'm currently using an approach involving a Context Provider to access the theme value across the entire application.

I'm also adding the styles individually in index.css by targeting the data-theme attribute. This is nice, but it can be quite tasking, hence my move towards a custom context hook. This would allow us to dynamically change colors across components in the application.

2025-01-3015-52-55-ezgif com-video-to-gif-converter

I ran into a slight blocker though. App.js uses a legacy React pattern — a class-based component which makes it a bit difficult to use the hook in this component, so I resorted to using the value from localStorage which is outside of the component/app life-cycle. So even if the value of theme in localStorage changes, the color — based on the ternary operation below — of the header won't change, because we do not trigger a re-render. Which is what the hook helps us achieve.

<div
     className="flex items-center ph3 ph4-l"
      style={{
         WebkitAppRegion: "drag",
          height: 75,
          background: currentTheme === "dark" ? "red" : "#F0F6FA",
          paddingTop: "20px",
          paddingBottom: "15px",
        }}
>

So, my question now is if it is possible to refactor App.js into a function-based component

@kaf-lamed-beyt kaf-lamed-beyt requested a review from a team as a code owner January 30, 2025 15:07
Copy link

welcome bot commented Jan 30, 2025

Thank you for submitting this PR!
A maintainer will be here shortly to review it.
We are super grateful, but we are also overloaded! Help us by making sure that:

  • The context for this PR is clear, with relevant discussion, decisions
    and stakeholders linked/mentioned.

  • Your contribution itself is clear (code comments, self-review for the
    rest) and in its best form. Follow the code contribution
    guidelines

    if they apply.

Getting other community members to do a review would be great help too on complex PRs (you can ask in the chats/forums). If you are unsure about something, just leave us a comment.
Next steps:

  • A maintainer will triage and assign priority to this PR, commenting on
    any missing things and potentially assigning a reviewer for high
    priority items.

  • The PR gets reviews, discussed and approvals as needed.

  • The PR is merged by maintainers when it has been approved and comments addressed.

We currently aim to provide initial feedback/triaging within two business days. Please keep an eye on any labelling actions, as these will indicate priorities and status of your contribution.
We are very grateful for your contribution!

@kaf-lamed-beyt kaf-lamed-beyt changed the title feat: add theme provider feat: add dark mode Jan 30, 2025
@kaf-lamed-beyt
Copy link
Contributor Author

Hi @lidel, kindly take a look at this when you get the chance. Thanks.

@SgtPooki
Copy link
Member

SgtPooki commented Feb 5, 2025

So, my question now is if it is possible to refactor App.js into a function-based component

@kaf-lamed-beyt I would love for all components in ipfs-webui to be functional components. That is the direction we're moving. However, since that will likely be a significant change, we should probably do that as a separate PR.

You can see an example of a simple function component that is also using redux-bundler-react at

export default connect(

@kaf-lamed-beyt
Copy link
Contributor Author

Oh! Thanks for the feedback, @SgtPooki! I'll take a look at the file you pointed me to now.

So, from the looks of things now, are you suggesting that i use the manual approach of targeting each element based on the styles in [data-theme="dark|light"] in index.css?

We can always keep the hook.

Comment on lines 77 to 79
<div className='mb4'>
<ThemeToggle />
</div>
Copy link
Member

@lidel lidel Feb 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 the space in the left NavBar is limited especially in ipfs-desktop where UI acts as native app. and window height is limited by default.

we want to add diagnostics screen at some point

perhaps it is better to move this toggle to top right corner where we already have two items:

image

thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, yeah! that sounds goood, @lidel!

i originally thought of placing it there, but couldn't locate the icons in the code. I'll try looking for them and update the theme toggle's position

Copy link
Member

@SgtPooki SgtPooki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some comments

Comment on lines 19 to 27
const [theme, setTheme] = React.useState<boolean>(() => {
const savedTheme =
typeof window !== 'undefined' && localStorage.getItem('theme')
if (savedTheme) return savedTheme === 'dark'
return window.matchMedia('prefers-color-scheme: dark').matches
})
React.useEffect(() => {
const htmlElem = document.documentElement
const currentTheme = theme ? 'dark' : 'light'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like we can use better names for theme and setTheme since it seems to be a boolean indicating whether dark theme is selected or not

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true. how does isDarkTheme and setDarkTheme sound?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perfect

}
}
const values: ThemeContextValues = {
currentTheme: theme as unknown as Theme,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

theme is boolean, not a Theme, so setting it to as unknown as Theme is wrong.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally, use of as (typescript casting) should be limited as much as possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for catching this. I'll update it.

Comment on lines 11 to 12
toggleTheme: () => void;
toggleThemeWithKey: (event: React.KeyboardEvent<HTMLButtonElement>) => void;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced we need both of these. Can toggleTheme accept an optional event and handle expected keys?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'll try refactoring this.

kaf-lamed-beyt and others added 8 commits February 11, 2025 21:06
Co-authored-by: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com>
Co-authored-by: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com>
Co-authored-by: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com>
Co-authored-by: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com>
Co-authored-by: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com>
Co-authored-by: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com>
Co-authored-by: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com>
@kaf-lamed-beyt
Copy link
Contributor Author

@lidel, I've moved the toggle from the navbar. Here's what it looks like now.

ipfs-webui-dark-theme-ezgif com-video-to-gif-converter

I still have to wrap up with the other routes. When I do, I'll push the changes.

cc: @SgtPooki

- previously, pretty much all the keys on the keyboard can trigger the theme toggle when it is focused. we don't want that. Instead we should only limit it to specific keys (spacebar & enter).
- include all the varying colors when the theme is dark on all routes
- extend the Box component to use the theme value instead of explicitly passing it in the style prop across the codebase
@kaf-lamed-beyt
Copy link
Contributor Author

done with this. @SgtPooki, @lidel, kindly review.
2025-02-1216-36-22-ezgif com-video-to-gif-converter

the explore route was quite tricky to work on. I couldn't locate the elements/components that are used to render data in the UI, that's why the one on the right still retained a white background.

perhaps, if anyone can point me to where they are exactly.

@kaf-lamed-beyt
Copy link
Contributor Author

@SgtPooki, @lidel, using this to bump your notification(s) respectively

Copy link
Member

@SgtPooki SgtPooki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI I set brave browser to prefer dark theme, reloaded the page, and it didn't take.

Also, I don't see an event listener for matchMedia so i'll probably add one..

there are a few minor nits i'm looking through and will probably update and then merge this.

@kaf-lamed-beyt
Copy link
Contributor Author

FYI I set brave browser to prefer dark theme, reloaded the page, and it didn't take.

Also, I don't see an event listener for matchMedia so i'll probably add one..

there are a few minor nits i'm looking through and will probably update and then merge this.

Oh okay, @SgtPooki, I'll wait for the changes.

@SgtPooki
Copy link
Member

Oh okay, @SgtPooki, I'll wait for the changes.

pushing up changes soon. I changed things so that we only save to local storage if it's different from the system settings. I also added file extensions to imports in theme-provider.tsx.

We should add file extensions to all imports, and also prefer useEffect as a direct import instead of using React.blah


In this video, you can see me change the theme settings in my browser and then see that webui updates automatically. Also, the setting persists after refresh.

webui.dark.theme.demo.mp4

@kaf-lamed-beyt
Copy link
Contributor Author

We should add file extensions to all imports, and also prefer useEffect as a direct import instead of using React.blah

oh! I'll take note of that. i also understand the preference for useEffect instead of React.useEffect. Old habits, haha.

I also can't see the video you attached BTW

image

@SgtPooki
Copy link
Member

I also can't see the video you attached BTW

try this GIF:

webui dark theme demo

Copy link
Member

@SgtPooki SgtPooki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems like there is a bit more work to do cleaning up old create-react-app cruft before we can fully fix the import paths.. there are issues with importing extensions..

i want to move the build for ipfs-webui to vite.. i think we will need to do that before addressing more build issues or import pathings.

Copy link
Member

@SgtPooki SgtPooki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm.. i pushed up some changes. @kaf-lamed-beyt please take a look, if you're good with it, I will merge this today

cc @lidel if you want to take a look but I won't block on you

@kaf-lamed-beyt
Copy link
Contributor Author

lgtm.. i pushed up some changes. @kaf-lamed-beyt please take a look, if you're good with it, I will merge this today

cc @lidel if you want to take a look but I won't block on you

oh alright. I'll do this now.

@kaf-lamed-beyt
Copy link
Contributor Author

kaf-lamed-beyt commented Feb 26, 2025

This looks good to me, @SgtPooki. I saw how you listened to prefers-color-scheme with matchMedia too. Fine work! 🍷

@SgtPooki SgtPooki merged commit d751fc6 into ipfs:main Feb 26, 2025
20 checks passed
@lidel lidel mentioned this pull request Feb 26, 2025
SgtPooki added a commit that referenced this pull request Feb 27, 2025
SgtPooki added a commit that referenced this pull request Feb 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature: dark mode
3 participants