Skip to content

Commit

Permalink
feat: update demo app with theme provider
Browse files Browse the repository at this point in the history
  • Loading branch information
stephanie56 committed Dec 10, 2024
1 parent bba0263 commit 7514937
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 13 deletions.
27 changes: 15 additions & 12 deletions apps/demo/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import './App.css'
import { Button } from '@repo/ui'
import "@repo/foundations/styles";
import { useState } from 'react';
import { useTheme } from './ThemeProvider';

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>
)
Expand All @@ -18,36 +18,39 @@ const SecondaryBrandIcon = () => (<svg xmlns="http://www.w3.org/2000/svg" width=


function App() {
const [brand, setBrand] = useState('brand-1');
const [mode, setMode] = useState<'light' | 'dark'>('light');
const [breakpoint, setBreakpoint] = useState('desktop');
const density = 'default';
const {
brand,
mode,
breakpoint,
setBrand,
setMode,
setBreakpoint
} = useTheme();

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

return (
<div className={bodyClasses}>
<main>
<div>
Radius Token Tango demo
</div>
<div></div>
<h1>Kitchen Sink</h1>
<div>
<button title={mode === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'} onClick={() => setMode((state) => state === 'dark' ? 'light' : 'dark')}>
<div className='control'>
<button title={mode === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'} onClick={() => setMode(mode === 'dark' ? 'light' : 'dark')}>
{mode === 'dark' ? <LightModeIcon /> : <DarkModeIcon />}
</button>
<button title={breakpoint === 'desktop' ? 'Switch to mobile view' : 'Switch to desktop view'} onClick={() => setBreakpoint((state) => state === 'desktop' ? 'mobile' : 'desktop')}>
<button title={breakpoint === 'desktop' ? 'Switch to mobile view' : 'Switch to desktop view'} onClick={() => setBreakpoint(breakpoint === 'desktop' ? 'mobile' : 'desktop')}>
{breakpoint === 'desktop' ? <MobileIcon /> : <DesktopIcon />}
</button>
<button title={brand === 'brand-1' ? 'Switch to hot brand' : 'Switch to default brand'} onClick={() => setBrand((state) => state === 'brand-1' ? 'hot-brand' : 'brand-1')}>
<button title={brand === 'brand-1' ? 'Switch to hot brand' : 'Switch to default brand'} onClick={() => setBrand(brand === 'brand-1' ? 'hot-brand' : 'brand-1')}>
{brand === 'brand-1' ? <SecondaryBrandIcon/> : <DefaultBrandIcon/>}
</button>
</div>
<div className='card'>
<Button label="Primary" variant='primary' />
<Button label="Secondary" variant='secondary' />
</div>
</div>
</main>
)
}

Expand Down
59 changes: 59 additions & 0 deletions apps/demo/src/ThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { createContext, useState, ReactNode, useEffect, useContext } from 'react';

type Brand = 'brand-1' | 'hot-brand';
type Mode = 'light' | 'dark';
type Breakpoint = 'desktop' | 'mobile';
type Density = 'default' | 'compact';

interface ThemeContextType {
brand: Brand;
mode: Mode;
breakpoint: Breakpoint;
density: Density;
setBrand: (brand: Brand) => void;
setMode: (mode: Mode) => void;
setBreakpoint: (breakpoint: Breakpoint) => void;
setDensity: (density: Density) => void;
bodyClasses: string;
}

const ThemeContext = createContext<ThemeContextType | undefined>(undefined);

export const ThemeProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
const [brand, setBrand] = useState<Brand>('brand-1');
const [mode, setMode] = useState<Mode>('light');
const [breakpoint, setBreakpoint] = useState<Breakpoint>('desktop');
const [density, setDensity] = useState<Density>('default');

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

useEffect(() => {
document.body.className = bodyClasses;
}, [bodyClasses]);

const contextValue: ThemeContextType = {
brand,
mode,
breakpoint,
density,
setBrand,
setMode,
setBreakpoint,
setDensity,
bodyClasses
};

return (
<ThemeContext.Provider value={contextValue}>
{children}
</ThemeContext.Provider>
);
};

export const useTheme = () => {
const context = useContext(ThemeContext);
if (context === undefined) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
};
8 changes: 8 additions & 0 deletions apps/demo/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,14 @@ body {
place-items: center;
min-width: 320px;
min-height: 100vh;
background-color: var(--semantic-static-background-color-default);
color: var(--semantic-static-text-color-default);
}

h1 {
font-size: 3.2em;
line-height: 1.1;
color: var(--semantic-static-text-color-default);
}

button {
Expand All @@ -54,6 +57,11 @@ button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}

.control {
display: flex;
justify-content: center;
gap: 0.5em;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
Expand Down
5 changes: 4 additions & 1 deletion apps/demo/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
import './index.css'
import { ThemeProvider } from './ThemeProvider.tsx'

createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
<ThemeProvider>
<App />
</ThemeProvider>
</StrictMode>,
)

0 comments on commit 7514937

Please sign in to comment.