Skip to content

Commit 6d66009

Browse files
committed
refactor: remove ChakraUI components; implement custom components and styles with Tailwind CSS; add Roboto Condensed font
1 parent 6e76d20 commit 6d66009

File tree

16 files changed

+211
-260
lines changed

16 files changed

+211
-260
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import useColorMode from '@/_foundation/hooks/useColorMode';
2+
import { fireEvent, render, screen } from '@testing-library/react';
3+
import { vi } from 'vitest';
4+
import { ColorModeSwitcher } from './index';
5+
6+
vi.mock('@/_foundation/hooks/useColorMode');
7+
8+
describe('ColorModeSwitcher', () => {
9+
it('renders the button', () => {
10+
vi.mocked(useColorMode).mockReturnValue({
11+
colorMode: 'light',
12+
toggleColorMode: vi.fn(),
13+
});
14+
15+
render(<ColorModeSwitcher />);
16+
const button = screen.getByRole('button');
17+
expect(button).toBeInTheDocument();
18+
});
19+
20+
it('displays the correct icon based on color mode', () => {
21+
vi.mocked(useColorMode).mockReturnValue({
22+
colorMode: 'light',
23+
toggleColorMode: vi.fn(),
24+
});
25+
26+
render(<ColorModeSwitcher />);
27+
expect(
28+
screen.getByLabelText('Switch to dark mode')
29+
).toBeInTheDocument();
30+
31+
vi.mocked(useColorMode).mockReturnValue({
32+
colorMode: 'dark',
33+
toggleColorMode: vi.fn(),
34+
});
35+
36+
render(<ColorModeSwitcher />);
37+
expect(
38+
screen.getByLabelText('Switch to light mode')
39+
).toBeInTheDocument();
40+
});
41+
42+
it('calls toggleColorMode on button click', () => {
43+
const toggleColorMode = vi.fn();
44+
vi.mocked(useColorMode).mockReturnValue({
45+
colorMode: 'light',
46+
toggleColorMode,
47+
});
48+
49+
render(<ColorModeSwitcher />);
50+
const button = screen.getByRole('button');
51+
fireEvent.click(button);
52+
expect(toggleColorMode).toHaveBeenCalledTimes(1);
53+
});
54+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import useColorMode from '@/_foundation/hooks/useColorMode';
2+
import { FaMoon } from 'react-icons/fa';
3+
import { MdSunny } from 'react-icons/md';
4+
5+
export const ColorModeSwitcher: React.FC<
6+
React.ButtonHTMLAttributes<HTMLButtonElement>
7+
> = (props) => {
8+
const { colorMode, toggleColorMode } = useColorMode();
9+
10+
return (
11+
<button
12+
className="text-current text-md p-2"
13+
onClick={() => {
14+
toggleColorMode();
15+
}}
16+
aria-label={`Switch to ${colorMode === 'dark' ? 'light' : 'dark'} mode`}
17+
{...props}
18+
>
19+
{colorMode === 'light' ? <FaMoon /> : <MdSunny />}
20+
</button>
21+
);
22+
};

client/src/_foundation/components/simple-suspense.test.tsx renamed to client/src/_foundation/components/simple-suspense/index.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { render, screen } from '@testing-library/react';
2-
import { SimpleSuspense } from './simple-suspense';
2+
import { SimpleSuspense } from '.';
33

44
describe('SimpleSuspense', () => {
55
it('renders fallback when children is undefined', () => {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { renderHook } from '@testing-library/react';
2+
import { vi } from 'vitest';
3+
import useColorMode from './useColorMode';
4+
5+
describe('useColorMode', () => {
6+
beforeEach(() => {
7+
localStorage.clear();
8+
document.documentElement.className = '';
9+
});
10+
11+
it('should initialize with light mode by default', () => {
12+
const { result } = renderHook(() => useColorMode());
13+
expect(result.current.colorMode).toBe('light');
14+
expect(document.documentElement.classList.contains('light')).toBe(true);
15+
});
16+
17+
it('should initialize with dark mode if prefers-color-scheme is dark', () => {
18+
window.matchMedia = vi.fn().mockImplementation((query) => ({
19+
matches: query === '(prefers-color-scheme: dark)',
20+
media: query,
21+
onchange: null,
22+
addListener: vi.fn(),
23+
removeListener: vi.fn(),
24+
}));
25+
26+
const { result } = renderHook(() => useColorMode());
27+
expect(result.current.colorMode).toBe('dark');
28+
expect(document.documentElement.classList.contains('dark')).toBe(true);
29+
});
30+
31+
it('should initialize with saved theme from localStorage', () => {
32+
localStorage.setItem('theme', 'dark');
33+
const { result } = renderHook(() => useColorMode());
34+
35+
expect(result.current.colorMode).toBe('dark');
36+
expect(document.documentElement.classList.contains('dark')).toBe(true);
37+
});
38+
});
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { useCallback, useEffect, useState } from 'react';
2+
3+
const useColorMode = () => {
4+
const [colorMode, setThemeMode] = useState<'dark' | 'light'>('light');
5+
6+
useEffect(() => {
7+
const savedTheme = localStorage.getItem('theme');
8+
if (savedTheme) {
9+
document.documentElement.classList.add(savedTheme);
10+
setThemeMode(savedTheme as 'dark' | 'light');
11+
} else {
12+
const prefersDarkScheme =
13+
typeof window.matchMedia === 'function' &&
14+
window.matchMedia('(prefers-color-scheme: dark)').matches;
15+
if (prefersDarkScheme) {
16+
document.documentElement.classList.add('dark');
17+
setThemeMode('dark');
18+
} else {
19+
document.documentElement.classList.add('light');
20+
setThemeMode('light');
21+
}
22+
}
23+
}, []);
24+
25+
const toggleColorMode = useCallback(() => {
26+
const cls = document.documentElement.classList;
27+
if (cls.contains('dark')) {
28+
cls.remove('dark');
29+
cls.add('light');
30+
localStorage.setItem('theme', 'light');
31+
setThemeMode('light');
32+
} else {
33+
cls.remove('light');
34+
cls.add('dark');
35+
localStorage.setItem('theme', 'dark');
36+
setThemeMode('dark');
37+
}
38+
}, []);
39+
40+
return { colorMode, toggleColorMode };
41+
};
42+
43+
export default useColorMode;

client/src/app/themes/theme.ts

Lines changed: 0 additions & 160 deletions
This file was deleted.

client/src/components/Subheader.tsx

Lines changed: 0 additions & 14 deletions
This file was deleted.

client/src/components/custom-link.tsx

Lines changed: 0 additions & 22 deletions
This file was deleted.

client/src/components/input-inline-label.tsx

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)