CodingTrain / thecodingtrain.com

All aboard the Coding Train! Choo choo! πŸš‚πŸŒˆβ€οΈ
https://thecodingtrain.com
MIT License
206 stars 108 forks source link

Add Dark Mode Feature to thecodingtrain Website #1504

Closed Yashasewi closed 4 months ago

Yashasewi commented 6 months ago

Dark Mode Feature Proposal

Description: As a user of thecodingtrain website, I often find myself browsing late at night or in low-light environments where a dark mode would be more comfortable for my eyes. I propose adding a dark mode feature to the website to enhance user experience and accessibility.

Benefits:

Additional Notes:

Preview:

Dark Mode

Desktop ![Dark Mode - Desktop](https://github.com/CodingTrain/thecodingtrain.com/assets/32950332/e5e92713-e2f8-4b45-a2d4-b80efb208411)
Small Screen (Mobile/Tablet) ![Dark Mode - Small Screen](https://github.com/CodingTrain/thecodingtrain.com/assets/32950332/359d2dc0-b7e6-4f14-a06e-b0f9f5aba7c9)

Light Mode

Desktop ![Light Mode - Desktop](https://github.com/CodingTrain/thecodingtrain.com/assets/32950332/7877cb64-c3c4-43cf-b09a-7636080f99b0)
Small Screen (Mobile/Tablet) ![Light Mode - Small Screen](https://github.com/CodingTrain/thecodingtrain.com/assets/32950332/5aab47c1-6138-48dd-9ea6-2bdf3817aa9a)

Feel free to provide any feedback or suggestions for improving this feature.

Once I complete the user preferences part, I will proceed to create a pull request. @shiffman

shiffman commented 6 months ago

Hi @Yashasewi thank you for this! This is widely requested and would be wonderful to integrate. @runemadsen this affects the design quite significantly, would you mind offering any feedback or thoughts before we proceed with any implementation?

runemadsen commented 6 months ago

This will be very cool! I would just make sure that the softness coming from the light grays are transferred to the dark mode layout by using blacks that are not fully black. I would make sure to use CSS variables so this is easy to tweak, and I'll be happy to take a look once the initial PR is in :)

shiffman commented 6 months ago

Thank you @runemadsen! It occurred to me that @jasontheillustrator might also want to take a look as dark mode may affect the illustrations and logos on the site as well. Thank you again @Yashasewi!

jasontheillustrator commented 6 months ago

Thanks Dan! This looks really good. I think the majority of the characters work just fine with dark mode. There's a couple that might be a little tricky depending on the black that is used for the background. This one for example is starting to look a bit weird because the eyes don't have much contrast to the background.

Screenshot 2024-03-19 at 12 32 32β€―PM

Right now it's probably ok. If the black background is toned down a bit, there will be less contrast with the eyes and mouth. Could we show a "dark mode" version of this character where the colors are tweaked slightly so that they show up better on a dark background? Either that or we just swap out this character for one that works better on light and dark mode.

runemadsen commented 6 months ago

Ah sorry, I completely missed the previews 😬 I think this is looking really good!

I would consider making the darks a bit lighter. It doesn't have to be much (perhaps closer to what we do on our site so it doesn't come off as contrasted. I think we should find a way to keep the soft red lines on the background, but we can take all of that once there's a PR to check.

Yashasewi commented 6 months ago

Hi everyone! Thank you for the valuable feedback and suggestions regarding the dark mode feature. I've been working on the implementation, I try to implement this feature as early as possible. Create an initial pr for feedback.

Yashasewi commented 6 months ago

Hi everyone,

Before proceeding with the pull request, I'd like to discuss the approach I've taken for implementing the dark mode feature.

Implementation Approach: Instead of using CSS variables, I've implemented dark mode using the CSS filter property, specifically

filter: invert(100%) hue-rotate(180deg);

This approach was inspired by the blog post Implementing dark mode in a handful of lines of CSS with CSS filters.

Advantages:

Potential Drawbacks:

Implementation Details: I've included the CSS and JavaScript code snippets for reference. Here's a brief overview:

Please ignore comments.

  1. CSS: The dark mode styles apply the filter property to the body element, effectively inverting the colors. Additional rules are included to handle specific elements like images, SVGs, code blocks, and list item markers.

    CSS Code πŸ‘‡πŸ‘‡ ```css body { /* background-color: var(--html-bg-color); */ filter: var(--filter-bg); /* color: var(--gray-dark); */ } html { /* background-color: #000000; */ background-color: var(--html-bg-color); /* background-color: #ffffff; */ } /* Do not invert media (revert the invert). */ img, video, iframe { /* filter: invert(100%) hue-rotate(180deg); */ filter: var(--filter-bg); /* filter: none; */ } svg { /* filter: invert(95%) hue-rotate(180deg); */ filter: var(--svg-filter-bg); /* filter: none; */ } /* Re-enable code block backgrounds. */ pre { /* filter: invert(6%); */ filter: var(--filter-pre-bg); } /* Improve contrast on list item markers. */ li::marker { /* color: #666; */ color: var(--color-li-bg); } ```
  2. JavaScript: The ThemeProvider component manages the theme state (dark) and provides a toggle function to switch between light and dark modes. It uses useLayoutEffect to apply the theme and persist the user's preference in localStorage.

    JavaScript code πŸ‘‡πŸ‘‡ ```Javascript import React, { useState, useLayoutEffect } from 'react'; /** * ThemeContext is a Context that holds the state of the theme and the method to toggle it * @type {React.Context<{dark: boolean, toggle: () => void}>} * @returns {JSX.Element} * @constructor * @param {boolean} dark - the current state of the theme * @param {() => void} toggle - the method to toggle the theme * @returns {JSX.Element} * */ export const ThemeContext = React.createContext({ dark: false, toggle: () => {} }); /** * ThemeProvider component is a Context Provider that passes down the state and the method to toggle the theme * @param children - the child components wrapped by the ThemeProvider * @returns {JSX.Element} * */ export default function ThemeProvider({ children }) { const [dark, setDark] = useState(false); useLayoutEffect(() => { const storedPreference = localStorage.getItem('darkModePreference'); if (storedPreference !== null) { setDark(JSON.parse(storedPreference)); } else { const prefersDarkMode = window.matchMedia( '(prefers-color-scheme: dark)' ).matches; setDark(prefersDarkMode); } }, []); useLayoutEffect(() => { applyTheme(); }, [dark]); const applyTheme = () => { let theme; if (dark) { theme = darkTheme; localStorage.setItem('darkModePreference', 'true'); } else { theme = lightTheme; localStorage.setItem('darkModePreference', 'false'); } const root = document.getElementsByTagName('html')[0]; root.style.cssText = theme.join(';'); }; const toggle = () => { const body = document.getElementsByTagName('body')[0]; body.style.cssText = 'transition: background .5s ease'; setDark(!dark); }; return ( {children} ); } // styles const lightTheme = [ '--filter-bg: none', // '--red-lightest: #fffcfc', '--html-bg-color: #ffffff', // '--gray-light: #ededed', // '--gray-dark: #3c3c3c' '--svg-filter-bg: none', '--filter-pre-bg: none', '--color-li-bg: inherit' ]; const darkTheme = [ '--filter-bg: invert(100%) hue-rotate(180deg)', // '--red-lightest: #1e1d20', // '--html-bg-color: #1e1d20', '--html-bg-color: #000000', // '--gray-light: #1e1d20', // '--gray-dark: #f5f5f5' '--svg-filter-bg: invert(100%) hue-rotate(180deg)', '--filter-pre-bg: invert(6%)', '--color-li-bg: #666' ]; ```

Updated preview πŸ‘‡πŸ‘‡

Dark Mode Desktop ![image](https://github.com/CodingTrain/thecodingtrain.com/assets/32950332/3c0e896e-9a18-4bc3-9fe3-442197f3fda7)

Next Steps: While this approach seems promising, I wanted to get your feedback and opinions before proceeding with the pull request. Are there any potential issues or concerns with using CSS filters for dark mode implementation? Is there a better approach that aligns with the project's design principles and ensures a seamless user experience?

I'm open to suggestions and willing to explore alternative implementations if deemed more suitable.

Please let me know your thoughts, and I'll be happy to address any concerns or make adjustments as needed.

Thank you for your valuable input and collaboration!

@shiffman @runemadsen @jasontheillustrator

runemadsen commented 6 months ago

Thanks for this description @Yashasewi. It's super helpful to understand the approach. Having thought about it for a bit, I would highly recommend to not do the dark mode with CSS filters, as all the brand colors will have random opposites applied without us being able to select those colors. I think a better solution would be to apply a theming class to the body and override the CSS variables that we're already using throughout the site. It won't be much more work, and it would allow us to pick the individual colors, which is much preferred compared to just inverting the entire color scheme.

Yashasewi commented 6 months ago

Thank you, @runemadsen, for your valuable feedback and suggestion. I appreciate you taking the time to review the CSS filter approach and providing your insights.

Based on your recommendation, I have implemented the dark mode feature using CSS variables and theming classes. This approach allows for better control over individual colors and ensures that the branding and design elements retain their intended appearance.

Remaining Issues:

While implementing the dark mode with CSS variables, I encountered a few instances where colors were hard-coded instead of using variables. I have identified and updated most of these instances, but there may still be some areas that need further attention.

If you or the team members notice any inconsistencies or issues with the dark mode implementation, please feel free to point them out, and I'll address them promptly.

Dark Mode Colors:

I have carefully selected the new dark mode colors to ensure a visually appealing and consistent experience. However, I would appreciate your feedback and input from the design team (@runemadsen, @jasontheillustrator) to ensure that the chosen colors align with the project's branding and design principles.

Next Steps:

I plan to create a pull request with the updated dark mode implementation. This will allow the all of you to review the changes, provide feedback, and contribute to further refinements if necessary.

Please let me know if you have any additional suggestions or concerns. I'm happy to make any necessary adjustments to ensure a successful integration of the dark mode feature.

Thank you again for your guidance and collaboration!

@shiffman @runemadsen @jasontheillustrator

runemadsen commented 6 months ago

That sounds amazing @Yashasewi! It's wonderful that you took the time to make the use of CSS variables even better. Can't wait to review the PR, so let me know when it's ready :)

Yashasewi commented 6 months ago

That sounds amazing @Yashasewi! It's wonderful that you took the time to make the use of CSS variables even better. Can't wait to review the PR, so let me know when it's ready :)

Thank you, @jasontheillustrator! I'm glad you liked CSS variables approach. I'll keep you updated and notify you once ready for review. Kind of little busy with some thingsπŸ₯²

Yashasewi commented 5 months ago

Hi everyone,

I've completed the implementation of the dark mode feature, and I'm excited to share that I've created a pull request for your review and feedback.

Pull Request: #1554 Dark Mode Implementation

In this pull request, I've addressed the following:

Please take a look at the pull request description for more details on the implementation, potential issues, screenshots, and next steps.

I would greatly appreciate it if you could review the changes and provide your feedback. I'm happy to address any concerns or make further adjustments as needed.

Thank you for your collaboration and support throughout this process. I'm looking forward to your valuable insights and working together to ensure a seamless integration of the dark mode feature.

@shiffman @runemadsen @jasontheillustrator