contracts-wizard icon indicating copy to clipboard operation
contracts-wizard copied to clipboard

Add Light/Dark Mode Theme Switcher with System Preference Support

Open Patrick-Ehimen opened this issue 9 months ago • 11 comments

It would be great if the Contracts Wizard could include the ability for users to switch between light mode and dark mode, or automatically use the system’s theme preference. This feature would improve the user experience, especially for those who prefer a dark interface for readability and eye comfort while also aligning with modern web development standards.

@ericglau, what do you think about this. Can I start working on it ?

Patrick-Ehimen avatar Mar 05 '25 19:03 Patrick-Ehimen

Thanks for the suggestion, this makes sense to add.

Currently the Wizard and its styling are spread across many different html pages (e.g. the pages in packages/ui/public when choosing different languages) and Svelte components (the Svelte apps in packages/ui/src).

One challenge here is to come up with a way to track the desired theme (light/dark) and keep it consistent when the user is moving between different parts of the UI.

Feel free to take a look at this, but if you have thoughts on an approach for tracking and applying the theme selection, please share as a first step so that we can ensure it fits with the overall design. Thanks!

ericglau avatar Mar 14 '25 16:03 ericglau

@ericglau Hey, can you assign this to me? I want to help

metanodreamer avatar Mar 18 '25 16:03 metanodreamer

@Patrick-Ehimen Hey, can you assign this to me? I want to help

I already started work on this

Patrick-Ehimen avatar Mar 18 '25 16:03 Patrick-Ehimen

Hey @Patrick-Ehimen we have a design for this which I believe may prove useful -

This is the prototype: https://www.figma.com/proto/nG5OZYG8UEyAT2dDJ0nXeJ/Wizard?page-id=1178%3A8494&node-id=1178-8495&p=f&viewport=-295%2C-430%2C0.32&t=LqNZq0CyFrfROINx-1&scaling=min-zoom&content-scaling=fixed&starting-point-node-id=1178%3A8495

you may need reset the prototype by tapping R first.

and this is the dev mode link: https://www.figma.com/design/gVk2uq2Z1U9aNjXv0nVSGP/Wizard%2F-Dark-Mode?node-id=0-1&m=dev

Let me or @ericglau know if we can help in any way.

makiopen avatar Mar 21 '25 10:03 makiopen

@makiopen this looks clean and intuitive, thanks for sharing.

Patrick-Ehimen avatar Mar 21 '25 22:03 Patrick-Ehimen

Thanks for the suggestion, this makes sense to add.

Currently the Wizard and its styling are spread across many different html pages (e.g. the pages in packages/ui/public when choosing different languages) and Svelte components (the Svelte apps in packages/ui/src).

One challenge here is to come up with a way to track the desired theme (light/dark) and keep it consistent when the user is moving between different parts of the UI.

Feel free to take a look at this, but if you have thoughts on an approach for tracking and applying the theme selection, please share as a first step so that we can ensure it fits with the overall design. Thanks!

had a busy week, i will try finishing this during the weekend

Patrick-Ehimen avatar Mar 21 '25 22:03 Patrick-Ehimen

Proposed Solution for Theme Management

After analyzing the codebase, I'd like to propose a centralized approach for managing themes across the Contracts Wizard UI. This solution ensures consistent theme handling across both Svelte components and static HTML pages.

Key Features

  • Global theme state management using Svelte store
  • Persistent theme preferences via localStorage
  • System theme preference detection
  • Consistent theme application across all UI components
  • Smooth theme transitions

Implementation Overview

  1. Theme Store Create a centralized store (packages/ui/src/common/stores/themeStore.ts) to manage the theme state.

  2. Theme Initialization (packages/ui/src/common/theme-init.ts) Early theme initialization to prevent flash of wrong theme.

  3. CSS Variables Define theme variables in packages/ui/src/common/styles/vars.css.

:root {
    /* Light theme defaults */
    --text-color: #333333;
    --background-color: #ffffff;
}

[data-theme="dark"] {
    --text-color: #ffffff;
    --background-color: #1a1a1a;
} 
  1. Theme Toggle Component Add a reusable theme toggle component that can be included in the navigation
<script lang="ts">
    import { theme } from '../stores/themeStore';
</script>

<button on:click={() => theme.toggle()} class="theme-toggle">
    {#if $theme === 'dark'}
        <svg><!-- Sun icon --></svg>
    {:else}
        <svg><!-- Moon icon --></svg>
    {/if}
</button>

Implementation Plan

  1. Add theme store and initialization scripts
  2. Update HTML entry points with theme initialization
  3. Replace hard-coded colors with theme variables
  4. Add theme toggle to navigation
  5. Update build configuration to include theme scripts

@ericglau @makiopen Would love to get feedback on this approach before proceeding with the implementation. Let me know if you'd like me to elaborate on any part of the solution.

Patrick-Ehimen avatar Mar 25 '25 10:03 Patrick-Ehimen

@Patrick-Ehimen Thanks for sharing, that approach sounds reasonable. Here are a few notes which may help with the implementation:

  1. There may be some updates needed for styles in files other than packages/ui/src/common/styles/vars.css.

    • For example, the styles in these files might be relevant: packages/ui/src/common/styles/global.css , packages/ui/src/solidity/App.svelte (and also App.svelte for the other languages: cairo, stellar, stylus).
    • If any of these have styles that are not using variables from packages/ui/src/common/styles/vars.css, it may make sense to change them to do so (if they are relevant for light/dark theme).
  2. The main HTML entry points which include the navigation bar are static HTML pages: packages/ui/public/index.html, packages/ui/public/cairo.html, packages/ui/public/stellar.html, packages/ui/public/stylus.html. Due to this, it may be difficult to use the Theme Toggle Component for the toggle button if that is a Svelte component. The Svelte app is only within the embedded <oz-wizard ...> section in those pages.

    • If you find that what you intended is not feasible due to this, a possible alternative could be to use URL parameters to communicate between the HTML pages and the Svelte app. You can find an example of that here and here where a version parameter is used.
  3. Wizard is also embedded in other sites, for example in https://docs.openzeppelin.com/contracts/5.x/wizard. The embedding method is described in https://github.com/OpenZeppelin/contracts-wizard?tab=readme-ov-file#embedding and is also the same method used in the HTML entry points above. The code for the embed is in packages/ui/src/embed.ts.

    • When embedded from other sites, it would be good to ignore the locally stored theme preference, as the theme setting should be determined by the site which embeds it. Instead, the site should be able to explicitly set the desired theme, for example by providing a parameter for <oz-wizard ...> (which relates to the URL parameters idea above, see example).

ericglau avatar Mar 25 '25 21:03 ericglau

Thank you for your inputs @ericglau If there are no objections or additional requirements, I would like to start working on this feature and tackle any arising issues along the way

Patrick-Ehimen avatar Mar 29 '25 21:03 Patrick-Ehimen

@Patrick-Ehimen Sounds good, thanks.

ericglau avatar Mar 30 '25 21:03 ericglau

@Patrick-Ehimen Sounds good, thanks.

LFG 🚀🚀

Patrick-Ehimen avatar Mar 31 '25 09:03 Patrick-Ehimen