Skip to content

Commit

Permalink
feat: 52 - add theming (#104)
Browse files Browse the repository at this point in the history
* core, light and dark theme variables

* import and forward the theme variables and css

* use/read/write theme mode context provider

* set background

* add toggle theme toggle button

* rename theme provider itnernal variables

* props.scss should only add the prefered theme for the prefers-color mode

* theme provider refactor (getSavedTheme + type)
  • Loading branch information
nickzoum authored Aug 4, 2022
1 parent 4cef6a2 commit eb86a72
Show file tree
Hide file tree
Showing 10 changed files with 364 additions and 11 deletions.
5 changes: 5 additions & 0 deletions src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Link } from 'react-router-dom';

import { useWeb3 } from '../../lib/web3/useWeb3';
import { useThemeMode } from '../../lib/themeProvider';

import logo from '../../assets/logo/logo.svg';

export default function Header() {
const { connectWallet, address } = useWeb3();
const { themeMode, toggleThemeMode } = useThemeMode();

const onConnectClick = () => {
connectWallet && connectWallet();
Expand All @@ -31,6 +33,9 @@ export default function Header() {
Connect Wallet
</button>
)}
<button className="ml-3" type="button" onClick={toggleThemeMode}>
{themeMode === 'light' ? '🌕' : '🌞'}
</button>
</nav>
</header>
);
Expand Down
2 changes: 2 additions & 0 deletions src/index.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@forward 'styles/theme/' as theme-*;

// Tailwind base includes its own version of CSS reset styles
@tailwind base;
@tailwind components;
Expand Down
101 changes: 101 additions & 0 deletions src/lib/themeProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import {
useEffect,
useState,
useContext,
createContext,
useCallback,
} from 'react';

export type ThemeMode = 'light' | 'dark';
export type SavedThemeMode = ThemeMode | null;

const storageName = 'themeMode';
const attributeName = 'data-theme-mode';
// name of css property indicating mode
const themeProperty = '--default-theme';

interface ThemeContextType {
setThemeMode: (theme: SavedThemeMode) => void;
toggleThemeMode: () => void;
themeMode: ThemeMode;
}

const ThemeContext = createContext<ThemeContextType>({
toggleThemeMode: () => void 0,
setThemeMode: () => void 0,
themeMode: getTheme(),
});

const storedMode = getSavedTheme();
if (storedMode) {
document.documentElement.setAttribute(attributeName, storedMode);
}

export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [savedTheme, setSavedTheme] = useState(getSavedTheme);
const themeMode = savedTheme ?? getDefaultBrowserTheme();

const toggleThemeMode = useCallback(
function () {
setSavedTheme(themeMode === 'dark' ? 'light' : 'dark');
},
[themeMode]
);

useEffect(() => {
window.addEventListener('storage', onStorageChange, false);
return () => window.removeEventListener('storage', onStorageChange, false);

function onStorageChange() {
setSavedTheme(getSavedTheme());
}
}, []);

// When the mode gets updated then update the document attribute
useEffect(() => {
if (savedTheme) {
document.documentElement.setAttribute(attributeName, savedTheme);
} else {
document.documentElement.removeAttribute(attributeName);
}
}, [savedTheme]);

// When the mode gets updated then update the persisted preference
useEffect(() => {
if (savedTheme) {
if (localStorage.getItem(storageName) !== savedTheme) {
localStorage.setItem(storageName, savedTheme);
}
} else {
if (localStorage.getItem(storageName)) {
localStorage.removeItem(storageName);
}
}
}, [savedTheme]);

return (
<ThemeContext.Provider
value={{ themeMode, setThemeMode: setSavedTheme, toggleThemeMode }}
>
{children}
</ThemeContext.Provider>
);
}

export function useThemeMode() {
return useContext(ThemeContext);
}

function getSavedTheme(): SavedThemeMode {
return localStorage.getItem(storageName) as SavedThemeMode;
}

export function getTheme(): ThemeMode {
return getSavedTheme() ?? getDefaultBrowserTheme();
}

export function getDefaultBrowserTheme(): ThemeMode {
return getComputedStyle(document.documentElement)
.getPropertyValue(themeProperty)
.trim() as ThemeMode;
}
4 changes: 4 additions & 0 deletions src/pages/App/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ main {
flex-grow: 1;
width: 100%;
}

body {
background: var(--bg);
}
25 changes: 14 additions & 11 deletions src/pages/App/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Web3Provider } from '../../lib/web3/useWeb3';
import { IndexerProvider } from '../../lib/web3/indexerProvider';
import { ThemeProvider } from '../../lib/themeProvider';

import { BrowserRouter, Routes, Route } from 'react-router-dom';

Expand All @@ -13,17 +14,19 @@ function App() {
return (
<Web3Provider>
<IndexerProvider>
<BrowserRouter>
<Header />
<main>
<Routes>
<Route index element={<div>Home</div>} />
<Route path="swap" element={<Swap />} />
<Route path="pool" element={<Pool />} />
<Route path="*" element={<div>Not found</div>} />
</Routes>
</main>
</BrowserRouter>
<ThemeProvider>
<BrowserRouter>
<Header />
<main>
<Routes>
<Route index element={<div>Home</div>} />
<Route path="swap" element={<Swap />} />
<Route path="pool" element={<Pool />} />
<Route path="*" element={<div>Not found</div>} />
</Routes>
</main>
</BrowserRouter>
</ThemeProvider>
</IndexerProvider>
</Web3Provider>
);
Expand Down
66 changes: 66 additions & 0 deletions src/styles/theme/core.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
$text: rgb(255, 255, 255);
$text-secondary: rgb(191, 191, 191);
$disabled: rgb(136, 136, 136);
$link: rgb(255, 255, 255);
$bg: conic-gradient(
from 120deg at 50% 100%,
rgb(78, 177, 232) 0deg,
rgba(18, 93, 135, 0.8) 180deg,
rgba(0, 0, 0, 0.8) 360deg
);
$input: rgb(255, 255, 255);
$ghost: rgba(255, 255, 255, 0.5);
$page-card: rgb(0, 0, 0);
$token-group: rgb(18, 92, 135);
$icon-button-bg: rgba(125, 125, 125, 0.4);
$icon-button-text: rgb(230, 230, 230);
$submit-button-bg: rgb(78, 177, 232);
$submit-button-text: rgb(255, 255, 255);
$ghost-button: rgb(187, 225, 246);
$card-border: rgb(78, 177, 232);
$dialog-bg: rgb(16, 16, 16);
$selected-token: rgb(12, 12, 12);
$badge-main: rgb(18, 93, 135);
$badge-secondary: rgb(168, 168, 168);
$badge-success: rgb(38, 128, 27);
$badge-info: rgb(224, 184, 121);
$badge-warning: rgb(218, 225, 137);
$badge-error: rgb(177, 81, 74);
$scrollbar: transparent;
$scrollbar-handle: rgb(217, 217, 217);
$scrollbar-handle-hover: rgb(217, 217, 217);
$tooltip-bg: rgb(51, 51, 51);
$tooltip-color: rgb(187, 187, 187);
$tooltip-border: rgb(18, 93, 135);

$map: (
'text': $text,
'text-secondary': $text-secondary,
'disabled': $disabled,
'link': $link,
'bg': $bg,
'input': $input,
'ghost': $ghost,
'page-card': $page-card,
'token-group': $token-group,
'icon-button-bg': $icon-button-bg,
'icon-button-text': $icon-button-text,
'submit-button-bg': $submit-button-bg,
'submit-button-text': $submit-button-text,
'ghost-button': $ghost-button,
'card-border': $card-border,
'dialog-bg': $dialog-bg,
'selected-token': $selected-token,
'badge-main': $badge-main,
'badge-secondary': $badge-secondary,
'badge-success': $badge-success,
'badge-info': $badge-info,
'badge-warning': $badge-warning,
'badge-error': $badge-error,
'scrollbar': $scrollbar,
'scrollbar-handle': $scrollbar-handle,
'scrollbar-handle-hover': $scrollbar-handle-hover,
'tooltip-bg': $tooltip-bg,
'tooltip-color': $tooltip-color,
'tooltip-border': $tooltip-border,
);
66 changes: 66 additions & 0 deletions src/styles/theme/dark.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
$text: rgb(255, 255, 255);
$text-secondary: rgb(191, 191, 191);
$disabled: rgb(136, 136, 136);
$link: rgb(255, 255, 255);
$bg: conic-gradient(
from 120deg at 50% 100%,
rgb(78, 177, 232) 0deg,
rgba(18, 93, 135, 0.8) 180deg,
rgba(0, 0, 0, 0.8) 360deg
);
$input: rgb(255, 255, 255);
$ghost: rgba(255, 255, 255, 0.5);
$page-card: rgb(0, 0, 0);
$token-group: rgb(18, 92, 135);
$icon-button-bg: rgba(125, 125, 125, 0.4);
$icon-button-text: rgb(230, 230, 230);
$submit-button-bg: rgb(78, 177, 232);
$submit-button-text: rgb(255, 255, 255);
$ghost-button: rgb(187, 225, 246);
$card-border: rgb(78, 177, 232);
$dialog-bg: rgb(16, 16, 16);
$selected-token: rgb(12, 12, 12);
$badge-main: rgb(18, 93, 135);
$badge-secondary: rgb(168, 168, 168);
$badge-success: rgb(38, 128, 27);
$badge-info: rgb(224, 184, 121);
$badge-warning: rgb(218, 225, 137);
$badge-error: rgb(177, 81, 74);
$scrollbar: transparent;
$scrollbar-handle: rgb(217, 217, 217);
$scrollbar-handle-hover: rgb(217, 217, 217);
$tooltip-bg: rgb(51, 51, 51);
$tooltip-color: rgb(187, 187, 187);
$tooltip-border: rgb(18, 93, 135);

$map: (
'text': $text,
'text-secondary': $text-secondary,
'disabled': $disabled,
'link': $link,
'bg': $bg,
'input': $input,
'ghost': $ghost,
'page-card': $page-card,
'token-group': $token-group,
'icon-button-bg': $icon-button-bg,
'icon-button-text': $icon-button-text,
'submit-button-bg': $submit-button-bg,
'submit-button-text': $submit-button-text,
'ghost-button': $ghost-button,
'card-border': $card-border,
'dialog-bg': $dialog-bg,
'selected-token': $selected-token,
'badge-main': $badge-main,
'badge-secondary': $badge-secondary,
'badge-success': $badge-success,
'badge-info': $badge-info,
'badge-warning': $badge-warning,
'badge-error': $badge-error,
'scrollbar': $scrollbar,
'scrollbar-handle': $scrollbar-handle,
'scrollbar-handle-hover': $scrollbar-handle-hover,
'tooltip-bg': $tooltip-bg,
'tooltip-color': $tooltip-color,
'tooltip-border': $tooltip-border,
);
4 changes: 4 additions & 0 deletions src/styles/theme/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@forward 'light.scss' as light-*;
@forward 'dark.scss' as dark-*;
@forward 'core.scss' as core-*;
@use './props.scss';
66 changes: 66 additions & 0 deletions src/styles/theme/light.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
$text: rgb(0, 0, 0);
$text-secondary: rgb(80, 80, 80);
$disabled: rgb(136, 136, 136);
$link: rgb(103, 159, 243);
$bg: conic-gradient(
from 120deg at 50% 100%,
rgb(136, 196, 227) 0deg,
rgba(85, 160, 203, 0.8) 180deg,
rgba(194, 194, 194, 0.8) 360deg
);
$input: rgb(0, 0, 0);
$ghost: rgba(0, 0, 0, 0.5);
$page-card: rgb(255, 255, 255);
$token-group: rgb(76, 142, 180);
$icon-button-bg: rgba(170, 169, 169, 0.4);
$icon-button-text: rgb(188, 188, 188);
$submit-button-bg: rgb(78, 177, 232);
$submit-button-text: rgb(0, 0, 0);
$ghost-button: rgb(71, 182, 241);
$card-border: rgb(152, 203, 231);
$dialog-bg: rgb(227, 227, 227);
$selected-token: rgb(218, 218, 218);
$badge-main: rgb(88, 170, 218);
$badge-secondary: rgb(168, 168, 168);
$badge-success: rgb(136, 190, 129);
$badge-info: rgb(224, 184, 121);
$badge-warning: rgb(218, 225, 137);
$badge-error: rgb(177, 81, 74);
$scrollbar: transparent;
$scrollbar-handle: rgb(217, 217, 217);
$scrollbar-handle-hover: rgb(217, 217, 217);
$tooltip-bg: rgb(207, 207, 207);
$tooltip-color: rgb(85, 85, 85);
$tooltip-border: rgb(49, 134, 183);

$map: (
'text': $text,
'text-secondary': $text-secondary,
'disabled': $disabled,
'link': $link,
'bg': $bg,
'input': $input,
'ghost': $ghost,
'page-card': $page-card,
'token-group': $token-group,
'icon-button-bg': $icon-button-bg,
'icon-button-text': $icon-button-text,
'submit-button-bg': $submit-button-bg,
'submit-button-text': $submit-button-text,
'ghost-button': $ghost-button,
'card-border': $card-border,
'dialog-bg': $dialog-bg,
'selected-token': $selected-token,
'badge-main': $badge-main,
'badge-secondary': $badge-secondary,
'badge-success': $badge-success,
'badge-info': $badge-info,
'badge-warning': $badge-warning,
'badge-error': $badge-error,
'scrollbar': $scrollbar,
'scrollbar-handle': $scrollbar-handle,
'scrollbar-handle-hover': $scrollbar-handle-hover,
'tooltip-bg': $tooltip-bg,
'tooltip-color': $tooltip-color,
'tooltip-border': $tooltip-border,
);
Loading

0 comments on commit eb86a72

Please sign in to comment.