Skip to content

Commit

Permalink
refactor(Callout): replace SCSS with tailwind-variants, adjust theming
Browse files Browse the repository at this point in the history
  • Loading branch information
websiddu committed Dec 22, 2024
1 parent ca816b2 commit a35fb28
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 290 deletions.
91 changes: 0 additions & 91 deletions lib/Callout/Callout.module.scss

This file was deleted.

66 changes: 58 additions & 8 deletions lib/Callout/Callout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import clsx from 'clsx';
import { tv } from 'tailwind-variants';
import {
CheckIcon,
CircleXIcon,
Expand All @@ -7,10 +7,56 @@ import {
LightbulbIcon,
TriangleAlertIcon,
} from 'lucide-react';
import styles from './Callout.module.scss';
import type { VariantProps } from 'tailwind-variants';

interface CalloutProps {
variant?: 'info' | 'tip' | 'warning' | 'success' | 'error' | 'note';
const callout = tv({
slots: {
base: 'mt-6 overflow-hidden rounded-xl border px-5 py-4 flex items-start space-x-3',
icon: 'mt-0.5 h-5 w-5',
content: 'flex-1 overflow-x-auto first:mt-0 last:mb-0',
},
variants: {
variant: {
info: {
base: 'border-zinc-500/20 bg-zinc-50/50 dark:border-zinc-500/30 dark:bg-zinc-500/10',
icon: 'text-zinc-500',
content: 'text-zinc-900 dark:text-zinc-200',
},
tip: {
base: 'border-emerald-500/20 bg-emerald-50/50 dark:border-emerald-500/30 dark:bg-emerald-500/10',
icon: 'text-emerald-600',
content: 'text-emerald-900 dark:text-emerald-200',
},
warning: {
base: 'border-amber-500/20 bg-amber-50/50 dark:border-amber-500/30 dark:bg-amber-500/10',
icon: 'text-amber-600',
content: 'text-amber-900 dark:text-amber-200',
},
success: {
base: 'border-green-500/20 bg-green-50/50 dark:border-green-500/30 dark:bg-green-500/10',
icon: 'text-green-600',
content: 'text-green-900 dark:text-green-200',
},
error: {
base: 'border-red-500/20 bg-red-50/50 dark:border-red-500/30 dark:bg-red-500/10',
icon: 'text-red-600',
content: 'text-red-900 dark:text-red-200',
},
note: {
base: 'border-sky-500/20 bg-sky-50/50 dark:border-sky-500/30 dark:bg-sky-500/10',
icon: 'text-sky-600',
content: 'text-sky-900 dark:text-sky-200',
},
},
},
defaultVariants: {
variant: 'info',
},
});

type CalloutVariant = VariantProps<typeof callout>;

interface CalloutProps extends CalloutVariant {
className?: string;
children: React.ReactNode | React.ReactNode[];
}
Expand All @@ -36,16 +82,20 @@ const variants = {
},
} as const;

const Callout = ({ variant = 'info', className, children }: CalloutProps) => {
const Callout = ({ variant = 'info', children }: CalloutProps) => {
const Icon = variants[variant].icon;

const { base, icon, content } = callout({
variant: variant,
});

return (
<div className={clsx(styles['callout'], styles[`${variant}`], className)}>
<div className={base()}>
<Icon
size={20}
className={styles['calloutIcon']}
className={icon()}
/>
<div className={styles['calloutContent']}>{children}</div>
<div className={content()}>{children}</div>
</div>
);
};
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@
"react-medium-image-zoom": "^5.2.12",
"react-router": "^7.0.2",
"remark-gfm": "^4.0.0",
"slugify": "^1.6.6"
"slugify": "^1.6.6",
"tailwind-variants": "^0.3.0"
},
"publishConfig": {
"access": "public"
Expand Down
28 changes: 26 additions & 2 deletions src/components/SideNav.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { NavLink } from 'react-router';
import { useTheme } from './Theme';

export const components = [
{
Expand Down Expand Up @@ -46,6 +47,11 @@ export const components = [
}[];

export const SideNav = () => {
const theme = useTheme();
const setTheme = (themeString: 'dark' | 'light') => {
theme.toggleTheme(themeString);
};

return (
<div className="min-w-[220px]">
<div className="sticky top-10">
Expand All @@ -57,14 +63,32 @@ export const SideNav = () => {
key={component.name}
className={({ isActive }) => {
const classNames =
'text-gray-700 hover:text-gray-900 px-4 py-1.5 hover:bg-slate-100 -ml-4 rounded-full';
return isActive ? `${classNames} bg-slate-100 font-medium` : classNames;
'text-gray-700 dark:text-gray-200 dark:hover:text-gray-800 hover:text-gray-900 px-4 py-1.5 hover:bg-slate-100 -ml-4 rounded-full';
return isActive
? `${classNames} bg-slate-100 dark:text-gray-700 font-medium`
: classNames;
}}
>
{component.name}
</NavLink>
))}
</div>

<div className="mt-10">
<button
className="text-xs uppercase"
onClick={() => setTheme('dark')}
>
Dark
</button>{' '}
|{' '}
<button
className="text-xs uppercase"
onClick={() => setTheme('light')}
>
Light
</button>
</div>
</div>
</div>
);
Expand Down
41 changes: 41 additions & 0 deletions src/components/Theme.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { createContext, useContext, ReactNode, useState, useEffect } from 'react';

type Theme = 'light' | 'dark';

interface ThemeContextProps {
theme: Theme;
toggleTheme: (_theme: Theme) => void;
}

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

export const ThemeProvider = ({ children }: { children: ReactNode }) => {
const localTheme = localStorage.getItem('theme') as Theme;
const [theme, setTheme] = useState<Theme>(localTheme ?? 'light');

useEffect(() => {
if (localTheme) {
setTheme(localTheme);
toggleTheme(localTheme);
}
}, []);

const toggleTheme = (_theme: 'dark' | 'light') => {
localStorage.setItem('theme', _theme);
setTheme(_theme);

document.documentElement.classList.add(_theme);
document.documentElement.classList.remove(_theme === 'dark' ? 'light' : 'dark');
document.documentElement.style.colorScheme = _theme;
};

return <ThemeContext.Provider value={{ theme, toggleTheme }}>{children}</ThemeContext.Provider>;
};

export const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
};
43 changes: 23 additions & 20 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { StepSamples } from './pages/StepSamples.tsx';
import { TypographySamples } from './pages/TypographySamples.tsx';
import { ImageSamples } from './pages/ImageSamples.tsx';
import { CodeSamples } from './pages/CodeSamples.tsx';
import { ThemeProvider } from './components/Theme.tsx';

const components: { [key: string]: React.ReactElement } = {
accordion: <AccordionSamples />,
Expand All @@ -23,26 +24,28 @@ const components: { [key: string]: React.ReactElement } = {

createRoot(document.getElementById('root')!).render(
<BrowserRouter>
<Routes>
<Route
path="/"
element={<App />}
/>
<ThemeProvider>
<Routes>
<Route
path="/"
element={<App />}
/>

<Route
path="components"
element={<ComponentsLayout />}
>
{Object.keys(components).map((key) => {
return (
<Route
key={key}
path={key}
element={components[key]}
/>
);
})}
</Route>
</Routes>
<Route
path="components"
element={<ComponentsLayout />}
>
{Object.keys(components).map((key) => {
return (
<Route
key={key}
path={key}
element={components[key]}
/>
);
})}
</Route>
</Routes>
</ThemeProvider>
</BrowserRouter>,
);
1 change: 1 addition & 0 deletions tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import tailwindTypography from '@tailwindcss/typography';
/** @type {import('tailwindcss').Config} */
export default {
content: ['./lib/**/*.tsx', './src/**/*.tsx'],
darkMode: 'class',
theme: {
extend: {},
},
Expand Down
Loading

0 comments on commit a35fb28

Please sign in to comment.