Skip to content

Commit 7514937

Browse files
author
Stephanie Zeng
committed
feat: update demo app with theme provider
1 parent bba0263 commit 7514937

File tree

4 files changed

+86
-13
lines changed

4 files changed

+86
-13
lines changed

apps/demo/src/App.tsx

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import './App.css'
22
import { Button } from '@repo/ui'
33
import "@repo/foundations/styles";
4-
import { useState } from 'react';
4+
import { useTheme } from './ThemeProvider';
55

66
const LightModeIcon = () => (<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" className="lucide lucide-sun"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></svg>
77
)
@@ -18,36 +18,39 @@ const SecondaryBrandIcon = () => (<svg xmlns="http://www.w3.org/2000/svg" width=
1818

1919

2020
function App() {
21-
const [brand, setBrand] = useState('brand-1');
22-
const [mode, setMode] = useState<'light' | 'dark'>('light');
23-
const [breakpoint, setBreakpoint] = useState('desktop');
24-
const density = 'default';
21+
const {
22+
brand,
23+
mode,
24+
breakpoint,
25+
setBrand,
26+
setMode,
27+
setBreakpoint
28+
} = useTheme();
2529

26-
const bodyClasses = [brand, mode, density, breakpoint].join(" ");
2730

2831
return (
29-
<div className={bodyClasses}>
32+
<main>
3033
<div>
3134
Radius Token Tango demo
3235
</div>
3336
<div></div>
3437
<h1>Kitchen Sink</h1>
35-
<div>
36-
<button title={mode === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'} onClick={() => setMode((state) => state === 'dark' ? 'light' : 'dark')}>
38+
<div className='control'>
39+
<button title={mode === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'} onClick={() => setMode(mode === 'dark' ? 'light' : 'dark')}>
3740
{mode === 'dark' ? <LightModeIcon /> : <DarkModeIcon />}
3841
</button>
39-
<button title={breakpoint === 'desktop' ? 'Switch to mobile view' : 'Switch to desktop view'} onClick={() => setBreakpoint((state) => state === 'desktop' ? 'mobile' : 'desktop')}>
42+
<button title={breakpoint === 'desktop' ? 'Switch to mobile view' : 'Switch to desktop view'} onClick={() => setBreakpoint(breakpoint === 'desktop' ? 'mobile' : 'desktop')}>
4043
{breakpoint === 'desktop' ? <MobileIcon /> : <DesktopIcon />}
4144
</button>
42-
<button title={brand === 'brand-1' ? 'Switch to hot brand' : 'Switch to default brand'} onClick={() => setBrand((state) => state === 'brand-1' ? 'hot-brand' : 'brand-1')}>
45+
<button title={brand === 'brand-1' ? 'Switch to hot brand' : 'Switch to default brand'} onClick={() => setBrand(brand === 'brand-1' ? 'hot-brand' : 'brand-1')}>
4346
{brand === 'brand-1' ? <SecondaryBrandIcon/> : <DefaultBrandIcon/>}
4447
</button>
4548
</div>
4649
<div className='card'>
4750
<Button label="Primary" variant='primary' />
4851
<Button label="Secondary" variant='secondary' />
4952
</div>
50-
</div>
53+
</main>
5154
)
5255
}
5356

apps/demo/src/ThemeProvider.tsx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import React, { createContext, useState, ReactNode, useEffect, useContext } from 'react';
2+
3+
type Brand = 'brand-1' | 'hot-brand';
4+
type Mode = 'light' | 'dark';
5+
type Breakpoint = 'desktop' | 'mobile';
6+
type Density = 'default' | 'compact';
7+
8+
interface ThemeContextType {
9+
brand: Brand;
10+
mode: Mode;
11+
breakpoint: Breakpoint;
12+
density: Density;
13+
setBrand: (brand: Brand) => void;
14+
setMode: (mode: Mode) => void;
15+
setBreakpoint: (breakpoint: Breakpoint) => void;
16+
setDensity: (density: Density) => void;
17+
bodyClasses: string;
18+
}
19+
20+
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
21+
22+
export const ThemeProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
23+
const [brand, setBrand] = useState<Brand>('brand-1');
24+
const [mode, setMode] = useState<Mode>('light');
25+
const [breakpoint, setBreakpoint] = useState<Breakpoint>('desktop');
26+
const [density, setDensity] = useState<Density>('default');
27+
28+
const bodyClasses = [brand, mode, density, breakpoint].join(" ");
29+
30+
useEffect(() => {
31+
document.body.className = bodyClasses;
32+
}, [bodyClasses]);
33+
34+
const contextValue: ThemeContextType = {
35+
brand,
36+
mode,
37+
breakpoint,
38+
density,
39+
setBrand,
40+
setMode,
41+
setBreakpoint,
42+
setDensity,
43+
bodyClasses
44+
};
45+
46+
return (
47+
<ThemeContext.Provider value={contextValue}>
48+
{children}
49+
</ThemeContext.Provider>
50+
);
51+
};
52+
53+
export const useTheme = () => {
54+
const context = useContext(ThemeContext);
55+
if (context === undefined) {
56+
throw new Error('useTheme must be used within a ThemeProvider');
57+
}
58+
return context;
59+
};

apps/demo/src/index.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@ body {
2828
place-items: center;
2929
min-width: 320px;
3030
min-height: 100vh;
31+
background-color: var(--semantic-static-background-color-default);
32+
color: var(--semantic-static-text-color-default);
3133
}
3234

3335
h1 {
3436
font-size: 3.2em;
3537
line-height: 1.1;
38+
color: var(--semantic-static-text-color-default);
3639
}
3740

3841
button {
@@ -54,6 +57,11 @@ button:focus-visible {
5457
outline: 4px auto -webkit-focus-ring-color;
5558
}
5659

60+
.control {
61+
display: flex;
62+
justify-content: center;
63+
gap: 0.5em;
64+
}
5765
@media (prefers-color-scheme: light) {
5866
:root {
5967
color: #213547;

apps/demo/src/main.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ import { StrictMode } from 'react'
22
import { createRoot } from 'react-dom/client'
33
import App from './App.tsx'
44
import './index.css'
5+
import { ThemeProvider } from './ThemeProvider.tsx'
56

67
createRoot(document.getElementById('root')!).render(
78
<StrictMode>
8-
<App />
9+
<ThemeProvider>
10+
<App />
11+
</ThemeProvider>
912
</StrictMode>,
1013
)

0 commit comments

Comments
 (0)