Skip to content

Commit 69823bd

Browse files
Merge pull request #44 from ShipFriend0516/feature/lightmode
[Feature] 라이트모드 추가
2 parents de74a89 + 8469af2 commit 69823bd

File tree

8 files changed

+101
-9
lines changed

8 files changed

+101
-9
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { IconType } from 'react-icons';
2+
3+
interface IconButtonProps {
4+
Icon: IconType;
5+
text?: string;
6+
size?: number;
7+
className?: string;
8+
onClick?: () => void;
9+
}
10+
11+
const IconButton = ({
12+
Icon,
13+
text,
14+
size,
15+
className,
16+
onClick,
17+
}: IconButtonProps) => {
18+
return (
19+
<button
20+
onClick={onClick}
21+
className={
22+
className || 'p-4 fill-current hover:bg-gray-200/50 rounded-md'
23+
}
24+
>
25+
<Icon size={size || 20} />
26+
{text && <span>{text}</span>}
27+
</button>
28+
);
29+
};
30+
export default IconButton;

app/entities/common/NavBar.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@ import { useEffect, useState } from 'react';
44
import Profile from '@/app/entities/common/Profile';
55

66
import profile from '@/app/public/profile.jpg';
7+
import IconButton from '@/app/entities/common/Button/IconButton';
8+
import { FaRegMoon, FaRegSun } from 'react-icons/fa';
9+
import useTheme from '@/app/hooks/useTheme';
10+
import { IoMoonSharp, IoSunny, IoSunnySharp } from 'react-icons/io5';
711
const NavBar = () => {
812
const [isFixed, setIsFixed] = useState(false);
13+
const { theme, toggleTheme } = useTheme();
914

1015
useEffect(() => {
1116
const handleScroll = () => {
@@ -36,7 +41,11 @@ const NavBar = () => {
3641
<Profile profileThumbnail={profile} username={'Jeongwoo Seo'} />
3742
</Link>
3843
</div>
39-
<ul className={'inline-flex max-w-5xl w-full justify-end gap-6 '}>
44+
<ul
45+
className={
46+
'inline-flex max-w-5xl w-full justify-end gap-4 items-center'
47+
}
48+
>
4049
<li>
4150
<Link href="/posts">Blog</Link>
4251
</li>
@@ -46,6 +55,13 @@ const NavBar = () => {
4655
<li>
4756
<Link href="/portfolio">Portfolio</Link>
4857
</li>
58+
<li>
59+
<IconButton
60+
onClick={toggleTheme}
61+
Icon={theme === 'light' ? IoSunnySharp : IoMoonSharp}
62+
size={20}
63+
/>
64+
</li>
4965
</ul>
5066
</div>
5167
</nav>

app/entities/post/detail/PostBody.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
import LoadingIndicator from '@/app/entities/common/Loading/LoadingIndicator';
33
import MDEditor from '@uiw/react-md-editor';
44
import PostTOC from '@/app/entities/post/detail/PostTOC';
5+
import useTheme from '@/app/hooks/useTheme';
56

67
interface Props {
78
content: string;
89
loading?: boolean;
910
}
1011

1112
const PostBody = ({ content, loading }: Props) => {
13+
const { theme } = useTheme();
1214
return (
1315
<div
1416
className={'max-w-full post-body px-4 py-16 min-h-[500px] relative '}
@@ -27,7 +29,7 @@ const PostBody = ({ content, loading }: Props) => {
2729
className={''}
2830
source={content}
2931
wrapperElement={{
30-
'data-color-mode': 'dark',
32+
'data-color-mode': theme,
3133
}}
3234
/>
3335
<PostTOC postContent={content || ''} />

app/entities/post/detail/PostHeader.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const PostHeader = ({
4747
return (
4848
<div
4949
className={
50-
'post-header h-[220px] md:h-[292px] relative overflow-hidden w-full text-center bg-gray-400/50'
50+
'post-header h-[220px] md:h-[292px] relative overflow-hidden w-full text-center bg-gray-400/40 text-white'
5151
}
5252
>
5353
<h1 className={'font-bold mb-4 pt-10 md:pt-20 text-3xl md:text-5xl '}>

app/entities/post/detail/PostTOC.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const PostTOC = ({ postContent }: { postContent: string }) => {
1212
};
1313

1414
return (
15-
<div className="fixed post-toc hidden 2xl:block w-[280px] top-[calc(50%+100px)] -translate-y-1/2 left-[calc(50%+524px)] transition-all text-sm bg-gray-100/80 rounded-md p-4 text-black">
15+
<div className="absolute post-toc hidden 2xl:block w-[280px] top-20 left-full ml-16 transition-all text-sm bg-gray-100/80 rounded-md p-4 text-black">
1616
<h4 className={'text-xl font-bold mb-2'}>📌 Table of Contents</h4>
1717
<ul className={'list-none'}>
1818
{parseHeadings(postContent).map((heading) => {

app/hooks/useTheme.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import useThemeStore from '@/app/stores/useThemeStore';
2+
import { useEffect } from 'react';
3+
4+
const useTheme = () => {
5+
const { theme, setTheme } = useThemeStore();
6+
const toggleTheme = () => {
7+
setTheme(theme === 'light' ? 'dark' : 'light');
8+
};
9+
10+
useEffect(() => {
11+
if (theme === 'dark') {
12+
document.body.classList.add('dark');
13+
} else {
14+
document.body.classList.remove('dark');
15+
}
16+
}, [theme]);
17+
18+
return { theme, toggleTheme };
19+
};
20+
21+
export default useTheme;

app/page.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export default function Home() {
4141
Frontend Developer
4242
</h1>
4343
</div>
44-
<p className="text-lg text-gray-200 max-w-2xl">
44+
<p className="text-lg text-default max-w-2xl">
4545
안녕하세요, 서정우입니다. 사용자 경험과 깔끔한 코드 작성에 중점을 두고
4646
있으며, 멈추지 않는 기술의 변화를 즐깁니다.
4747
</p>
@@ -60,22 +60,22 @@ export default function Home() {
6060
</div>
6161
<div className="grid gap-4">
6262
<h2 className="text-2xl font-semibold">About Me</h2>
63-
<p className="text-gray-200">
63+
<p className="text-default">
6464
프론트엔드 개발자로서 React, Next.js, TypeScript를 주로 사용합니다.
6565
항상 사용자 입장에서 생각하고, 성능 최적화에 관심이 많으며, 지속적인
6666
학습과 성장을 추구합니다.
6767
</p>
6868
<div className="flex gap-4">
6969
<a href={'https://github.com/ShipFriend0516'} target={'_blank'}>
70-
<FaGithub className="w-5 h-5 text-gray-200 hover:text-gray-100 hover:scale-125 transition cursor-pointer" />
70+
<FaGithub className="w-5 h-5 text-default hover:text-gray-100 hover:scale-125 transition cursor-pointer" />
7171
</a>
7272
<a
7373
href={
7474
'https://www.linkedin.com/in/%EC%A0%95%EC%9A%B0-%EC%84%9C-9a0b79312/'
7575
}
7676
target={'_blank'}
7777
>
78-
<FaLinkedin className="w-5 h-5 text-gray-200 hover:text-gray-100 hover:scale-125 transition cursor-pointer" />
78+
<FaLinkedin className="w-5 h-5 text-default hover:text-gray-100 hover:scale-125 transition cursor-pointer" />
7979
</a>
8080
</div>
8181
</div>
@@ -107,7 +107,7 @@ export default function Home() {
107107
/>
108108
</div>
109109
<h3 className="font-medium mb-2">{post.title}</h3>
110-
<p className="text-sm text-gray-200">
110+
<p className="text-sm text-default">
111111
{post.subTitle && post.subTitle.slice(0, 80)}
112112
</p>
113113
</Link>

app/stores/useThemeStore.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { create } from 'zustand';
2+
import { persist } from 'zustand/middleware';
3+
4+
type Theme = 'light' | 'dark';
5+
6+
interface ThemeState {
7+
theme: 'light' | 'dark';
8+
setTheme: (theme: Theme) => void;
9+
}
10+
11+
const useThemeStore = create(
12+
persist<ThemeState>(
13+
(set) => ({
14+
theme: 'dark',
15+
setTheme: (theme: Theme) => set({ theme }),
16+
}),
17+
{
18+
name: 'theme-storage',
19+
}
20+
)
21+
);
22+
23+
export default useThemeStore;

0 commit comments

Comments
 (0)