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(wallet): add darkmode/lightmode theme selection logic #4053

Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/core/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export * from './KioskClientProvider';
export * from './QR';

export * from './providers';
44 changes: 44 additions & 0 deletions apps/core/src/components/providers/ThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { PropsWithChildren, useState, useEffect } from 'react';
import { Theme } from '../../enums';
import { ThemeContext } from '../../contexts';

interface ThemeProviderProps {
appId: string;
}

export function ThemeProvider({ children, appId }: PropsWithChildren<ThemeProviderProps>) {
const storageKey = `theme_${appId}`;
const [theme, setTheme] = useState<Theme>(() => {
if (typeof window !== 'undefined') {
const storedTheme = localStorage.getItem(storageKey);
if (storedTheme) {
return storedTheme as Theme;
} else {
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)').matches;
return prefersDarkScheme ? Theme.Dark : Theme.Light;
}
}
return Theme.Light;
});

useEffect(() => {
if (typeof window !== 'undefined') {
localStorage.setItem(storageKey, theme);
}
document.documentElement.classList.toggle(Theme.Dark, theme === Theme.Dark);
}, [theme, storageKey]);

return (
<ThemeContext.Provider
value={{
theme,
setTheme,
}}
>
{children}
</ThemeContext.Provider>
);
}
5 changes: 5 additions & 0 deletions apps/core/src/components/providers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export * from './KioskClientProvider';
export * from './ThemeProvider';
15 changes: 15 additions & 0 deletions apps/core/src/contexts/ThemeContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { createContext } from 'react';
import { Theme } from '../enums';

export interface ThemeContextType {
theme: Theme;
setTheme: (theme: Theme) => void;
}

export const ThemeContext = createContext<ThemeContextType>({
theme: Theme.Light,
setTheme: () => {},
});
4 changes: 4 additions & 0 deletions apps/core/src/contexts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export * from './ThemeContext';
4 changes: 4 additions & 0 deletions apps/core/src/enums/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export * from './theme.enums';
7 changes: 7 additions & 0 deletions apps/core/src/enums/theme.enums.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export enum Theme {
Light = 'light',
Dark = 'dark',
}
1 change: 1 addition & 0 deletions apps/core/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ export * from './useGetAllOwnedObjects';
export * from './useGetTimelockedStakedObjects';
export * from './useGetActiveValidatorsInfo';
export * from './useCursorPagination';
export * from './useTheme';

export * from './stake';
12 changes: 12 additions & 0 deletions apps/core/src/hooks/useTheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
import { useContext } from 'react';
import { ThemeContext, ThemeContextType } from '../contexts';

export const useTheme = (): ThemeContextType => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
};
2 changes: 2 additions & 0 deletions apps/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ export * from './components';
export * from './utils';
export * from './hooks';
export * from './constants';
export * from './contexts';
export * from './enums';
9 changes: 7 additions & 2 deletions apps/wallet-dashboard/app/(protected)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@ import { Button } from '@iota/apps-ui-kit';
import { redirect } from 'next/navigation';
import { Sidebar } from './components';
import { TopNav } from './components/top-nav/TopNav';
import { useTheme } from '@/contexts';
import { Theme, useTheme } from '@iota/core';

function DashboardLayout({ children }: PropsWithChildren): JSX.Element {
const { connectionStatus } = useCurrentWallet();
const { theme, toggleTheme } = useTheme();
const { theme, setTheme } = useTheme();

const toggleTheme = () => {
const newTheme = theme === Theme.Light ? Theme.Dark : Theme.Light;
setTheme(newTheme);
};
const account = useCurrentAccount();
useEffect(() => {
if (connectionStatus !== 'connected' && !account) {
Expand Down
6 changes: 4 additions & 2 deletions apps/wallet-dashboard/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ function HomeDashboardPage(): JSX.Element {
<div className="flex max-w-sm flex-col items-center gap-8 text-center">
<div className="flex flex-col items-center gap-4">
<span className="text-headline-sm text-neutral-40">Welcome to</span>
<h1 className="text-display-lg text-neutral-10">IOTA Wallet</h1>
<h1 className="text-display-lg text-neutral-10 dark:text-neutral-100">
IOTA Wallet
</h1>
<span className="text-title-lg text-neutral-40">
Connecting you to the decentralized web and IOTA network
</span>
</div>
<div className="[&_button]:!bg-neutral-90">
<div className="[&_button]:!bg-neutral-90 [&_button]:dark:!bg-neutral-20">
<ConnectButton connectText="Connect" />
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// SPDX-License-Identifier: Apache-2.0

import { Button, ButtonSize, ButtonType, Panel } from '@iota/apps-ui-kit';
import { Theme, useTheme } from '@/contexts';
import { useState } from 'react';
import { StakeDialog } from '../Dialogs';
import { Theme, useTheme } from '@iota/core';

export function StartStaking() {
const { theme } = useTheme();
Expand Down
38 changes: 0 additions & 38 deletions apps/wallet-dashboard/contexts/ThemeContext.tsx

This file was deleted.

1 change: 0 additions & 1 deletion apps/wallet-dashboard/contexts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,3 @@
// SPDX-License-Identifier: Apache-2.0

export * from './PopupContext';
export * from './ThemeContext';
4 changes: 2 additions & 2 deletions apps/wallet-dashboard/providers/AppProviders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { useState } from 'react';
import { growthbook } from '@/lib/utils';
import { Popup } from '@/components/Popup';
import { Toaster } from 'react-hot-toast';
import { ThemeProvider } from '@/contexts';
import { ThemeProvider } from '@iota/core';

growthbook.init();

Expand All @@ -36,7 +36,7 @@ export function AppProviders({ children }: React.PropsWithChildren) {
},
]}
>
<ThemeProvider>
<ThemeProvider appId="dashboard">
<PopupProvider>
{children}
<Toaster
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ import {
ImageType,
} from '@iota/apps-ui-kit';
import { ampli } from '_src/shared/analytics/ampli';
import { Theme, useTheme } from '@iota/core';

function MenuList() {
const { theme, setTheme } = useTheme();

const navigate = useNavigate();
const activeAccount = useActiveAccount();
const networkUrl = useNextMenuUrl(true, '/network');
Expand Down Expand Up @@ -77,6 +80,10 @@ function MenuList() {
window.open(FAQ_LINK, '_blank', 'noopener noreferrer');
}

function toggleTheme() {
const newTheme = theme === Theme.Light ? Theme.Dark : Theme.Light;
setTheme(newTheme);
}
const autoLockSubtitle = handleAutoLockSubtitle();
const MENU_ITEMS = [
{
Expand All @@ -99,8 +106,7 @@ function MenuList() {
{
title: 'Themes',
icon: <DarkMode />,
onClick: () => {},
isDisabled: true,
onClick: toggleTheme,
},
{
title: 'Reset',
Expand All @@ -114,12 +120,7 @@ function MenuList() {
<div className="flex h-full w-full flex-col justify-between">
<div className="flex flex-col">
{MENU_ITEMS.map((item, index) => (
<Card
key={index}
type={CardType.Default}
onClick={item.onClick}
isDisabled={item.isDisabled}
>
<Card key={index} type={CardType.Default} onClick={item.onClick}>
<CardImage type={ImageType.BgSolid}>
<div className="flex h-10 w-10 items-center justify-center rounded-full text-neutral-10 [&_svg]:h-5 [&_svg]:w-5">
<span className="text-2xl">{item.icon}</span>
Expand Down
32 changes: 17 additions & 15 deletions apps/wallet/src/ui/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { setAttributes } from '_src/shared/experimentation/features';
import initSentry from '_src/ui/app/helpers/sentry';
import store from '_store';
import { thunkExtras } from '_store/thunk-extras';
import { KioskClientProvider } from '@iota/core';
import { KioskClientProvider, ThemeProvider } from '@iota/core';
import { GrowthBookProvider } from '@growthbook/growthbook-react';
import { IotaClientProvider } from '@iota/dapp-kit';
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client';
Expand Down Expand Up @@ -96,20 +96,22 @@ function AppWrapper() {
>
<KioskClientProvider>
<AccountsFormProvider>
<UnlockAccountProvider>
<div
className={cn(
'relative flex h-screen max-h-popup-height min-h-popup-minimum w-popup-width flex-col flex-nowrap items-center justify-center overflow-hidden',
isFullscreen && 'rounded-xl shadow-lg',
)}
>
<ErrorBoundary>
<App />
</ErrorBoundary>
<div id="overlay-portal-container"></div>
<div id="toaster-portal-container"></div>
</div>
</UnlockAccountProvider>
<ThemeProvider appId="wallet">
<UnlockAccountProvider>
<div
className={cn(
'relative flex h-screen max-h-popup-height min-h-popup-minimum w-popup-width flex-col flex-nowrap items-center justify-center overflow-hidden',
isFullscreen && 'rounded-xl shadow-lg',
)}
>
<ErrorBoundary>
<App />
</ErrorBoundary>
<div id="overlay-portal-container"></div>
<div id="toaster-portal-container"></div>
</div>
</UnlockAccountProvider>
</ThemeProvider>
</AccountsFormProvider>
</KioskClientProvider>
</IotaClientProvider>
Expand Down
Loading