Skip to content

Commit 1272ecd

Browse files
authored
Navigation 사용성 개선 및 부가 기능 추가 (#191)
* refactor(NavigationLink): separate data and views * feat: refactor NavigationBar * feat: create PostTitle on NavigationBar * fix: content id duplication issues * fix: google font error
1 parent c422c5a commit 1272ecd

File tree

7 files changed

+200
-73
lines changed

7 files changed

+200
-73
lines changed

src/components/NavigationBar/NavigationBar.tsx

Lines changed: 168 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,16 @@
1-
import { useState } from 'react';
1+
import React, { useEffect, useState } from 'react';
22
import classNames from 'classnames';
33
import dynamic from 'next/dynamic';
4-
import { Noto_Sans_KR } from 'next/font/google';
54
import Link from 'next/link';
65
import { useRouter } from 'next/router';
76
import { FaGithub } from 'react-icons/fa';
87
import Icon from '../icons';
9-
import { Item } from './Item';
108
import styles from './NavigationBar.module.scss';
119

1210
const ThemeToggleButton = dynamic(() => import('./ThemeToggleButton'), {
1311
ssr: false,
1412
});
1513

16-
const notoSans = Noto_Sans_KR({
17-
weight: '500',
18-
style: ['normal'],
19-
subsets: ['latin'],
20-
});
21-
2214
// TODO - show floating menu button when display size is under sm
2315
const NavigationBar = () => {
2416
const [isOpen, setIsOpen] = useState(false);
@@ -55,30 +47,10 @@ const NavigationBar = () => {
5547
'mx-auto'
5648
)}
5749
>
58-
<div
59-
className={classNames(
60-
'left',
61-
'flex',
62-
'items-center',
63-
'gap-2',
64-
'sm:gap-0'
65-
)}
66-
>
67-
<Link
68-
className={classNames(notoSans.className, styles.title)}
69-
href="/"
70-
>
71-
BenLog
72-
</Link>
73-
</div>
74-
<div className={classNames('hidden', 'sm:flex')}>
75-
<ThemeToggleButton />
76-
<NavigationLinks />
77-
</div>
78-
<div className={classNames('flex', 'sm:hidden')}>
79-
<ThemeToggleButton />
80-
<Icon type="hamburger" onClick={toggleHamburgerIcon} />
81-
</div>
50+
<Left />
51+
<Middle />
52+
<Right />
53+
<Hidden onClick={toggleHamburgerIcon} />
8254
</div>
8355
{/** hidden part of NavigationBar */}
8456
{isOpen ? (
@@ -92,32 +64,174 @@ const NavigationBar = () => {
9264

9365
export default NavigationBar;
9466

95-
const NavigationLinks = () => {
67+
const Left = () => {
68+
return (
69+
<div
70+
className={classNames(
71+
'left',
72+
'flex',
73+
'items-center',
74+
'gap-2',
75+
'sm:gap-0'
76+
)}
77+
>
78+
<Logo />
79+
</div>
80+
);
81+
};
82+
83+
const Logo = () => {
84+
return (
85+
<Link
86+
className={classNames(styles.title)}
87+
href="/"
88+
style={{ fontFamily: 'Noto Sans KR' }}
89+
>
90+
BenLog
91+
</Link>
92+
);
93+
};
94+
95+
const Right = () => {
96+
return (
97+
<div className={classNames('hidden', 'sm:flex')}>
98+
<ThemeToggleButton />
99+
<NavigationLinks />
100+
</div>
101+
);
102+
};
103+
104+
const Middle = () => {
96105
const router = useRouter();
106+
const [isShowing, setIsShowing] = useState(false);
107+
const [postTitle, setPostTitle] = useState('');
108+
109+
useEffect(() => {
110+
const isPostPath = getSubDomain(router.pathname) === 'posts';
111+
setIsShowing(isPostPath);
112+
}, [router.pathname]);
113+
114+
useEffect(() => {
115+
const handler = () => {
116+
const title = document.querySelector('.post-title');
117+
118+
if (!title) return;
119+
120+
setPostTitle(title.textContent || '');
121+
};
122+
123+
handler();
124+
125+
router.events.on('routeChangeComplete', handler);
126+
127+
return () => {
128+
router.events.off('routeChangeComplete', handler);
129+
};
130+
}, [router.events]);
131+
97132
return (
98-
<>
99-
<Link
100-
className={classNames('w-full', 'text-center', 'flex', 'items-center')}
101-
href="/posts"
102-
>
103-
<Item current={getSubDomain(router.pathname) === 'posts'}>Posts</Item>
104-
</Link>
105-
<Link
106-
className={classNames('w-full', 'text-center', 'flex', 'items-center')}
107-
href="/about"
108-
>
109-
<Item current={getSubDomain(router.pathname) === 'posts'}>About</Item>
110-
</Link>
133+
<div
134+
className={classNames(
135+
'hidden',
136+
'md:flex',
137+
'flex-col',
138+
'justify-center',
139+
'items-center',
140+
'w-full',
141+
'text-center'
142+
)}
143+
>
144+
{postTitle}
145+
</div>
146+
);
147+
};
148+
149+
interface HiddenComponentProps {
150+
onClick?: React.MouseEventHandler<HTMLDivElement>;
151+
}
152+
153+
const Hidden = ({ onClick }: HiddenComponentProps) => {
154+
return (
155+
<div className={classNames('flex', 'sm:hidden')}>
156+
<ThemeToggleButton />
157+
<Icon type="hamburger" onClick={onClick} />
158+
</div>
159+
);
160+
};
161+
162+
interface NavigationLinkProps {
163+
href: string;
164+
children?: React.ReactNode;
165+
}
166+
167+
const getPathname = (href: string) => {
168+
if (href[0] !== '/') {
169+
return href;
170+
}
171+
172+
return href.slice(1);
173+
};
174+
175+
const NavigationLink = ({ href, children }: NavigationLinkProps) => {
176+
const router = useRouter();
177+
const pathname = getPathname(href);
178+
const isExternalLink = href === pathname;
179+
180+
return (
181+
<li className={classNames('w-full', 'text-center', 'flex', 'items-center')}>
111182
<Link
112-
className={classNames('w-full', 'text-center', 'flex', 'items-center')}
113-
href="https://github.com/mrbartrns"
114-
rel="noopener noreferrer"
115-
target="_blank"
183+
href={href}
184+
rel={isExternalLink ? 'noopener noreferrer' : undefined}
185+
target={isExternalLink ? '_blank' : undefined}
186+
title={typeof children === 'string' ? children : pathname}
187+
className={classNames(
188+
'flex',
189+
'justify-center',
190+
'items-center',
191+
'w-full',
192+
'select-none',
193+
'transition-all',
194+
'py-1',
195+
'px-2',
196+
'font-medium',
197+
'text-zinc-600',
198+
'dark:text-zinc-300',
199+
{
200+
'text-zinc-800': getSubDomain(router.pathname) === pathname,
201+
'dark:text-zinc-100': getSubDomain(router.pathname) === pathname,
202+
},
203+
'hover:text-zinc-800',
204+
'dark:hover:text-zinc-100'
205+
)}
116206
>
117-
<Item>
118-
<FaGithub className={classNames('text-xl')} />
119-
</Item>
207+
{children}
120208
</Link>
209+
</li>
210+
);
211+
};
212+
213+
const NavigationLinks = () => {
214+
const links = [
215+
{
216+
href: '/posts',
217+
children: 'Posts',
218+
},
219+
{
220+
href: '/about',
221+
children: 'About',
222+
},
223+
{
224+
href: 'https://github.com/mrbartrns',
225+
children: <FaGithub className={classNames('text-xl')} />,
226+
},
227+
];
228+
return (
229+
<>
230+
{links.map((link) => (
231+
<NavigationLink key={link.href} href={link.href}>
232+
{link.children}
233+
</NavigationLink>
234+
))}
121235
</>
122236
);
123237
};

src/components/NavigationBar/ThemeToggleButton.tsx

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,33 @@
11
import classNames from 'classnames';
22
import { MdOutlineLightMode, MdOutlineDarkMode } from 'react-icons/md';
33
import useTheme from '~/lib/styles/useTheme';
4-
import { Item } from './Item';
54
import type { Theme } from '~/lib/styles/types';
65

76
const ThemeToggleButton = () => {
87
const [theme, toggle] = useTheme();
98

109
return (
11-
<Item onClick={toggle}>
10+
<div
11+
className={classNames(
12+
'flex',
13+
'justify-center',
14+
'items-center',
15+
'w-full',
16+
'select-none',
17+
'transition-all',
18+
'cursor-pointer',
19+
'font-medium',
20+
'py-1',
21+
'px-2',
22+
'dark:text-zinc-300',
23+
'dark:hover:text-zinc-100',
24+
'text-zinc-600',
25+
'hover:text-zinc-800'
26+
)}
27+
onClick={toggle}
28+
>
1229
<ThemeToggleIcon theme={theme} />
13-
</Item>
30+
</div>
1431
);
1532
};
1633

src/components/Post/PostDetail/PostAside.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const PostAside = () => {
5555
<ul className={classNames('w-full', 'text-[color:var(--primary-variant)]')}>
5656
{heads.map((head) => (
5757
<li
58-
key={head.textContent}
58+
key={`${head.textContent}-${head.dataset.index}`}
5959
className={classNames('text-[90%]', 'leading-[1.7]', {
6060
'font-bold': activeIndex === Number(head.dataset.index),
6161
})}
@@ -70,7 +70,7 @@ const PostAside = () => {
7070
>
7171
<a
7272
className={classNames('hover:underline')}
73-
href={`#${setElementId(head.textContent)}`}
73+
href={`#${setElementId(head.textContent)}-${head.dataset.index}`}
7474
>
7575
{head.textContent}
7676
</a>

src/components/Post/PostDetail/PostContent.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,21 +59,21 @@ const Content = ({ content }: Props) => {
5959
components={{
6060
h1({ index, children }) {
6161
return (
62-
<h1 data-index={index} id={setElementId(children)}>
62+
<h1 data-index={index} id={`${setElementId(children)}-${index}`}>
6363
{children}
6464
</h1>
6565
);
6666
},
6767
h2({ index, children }) {
6868
return (
69-
<h2 data-index={index} id={setElementId(children)}>
69+
<h2 data-index={index} id={`${setElementId(children)}-${index}`}>
7070
{children}
7171
</h2>
7272
);
7373
},
7474
h3({ index, children }) {
7575
return (
76-
<h3 data-index={index} id={setElementId(children)}>
76+
<h3 data-index={index} id={`${setElementId(children)}-${index}`}>
7777
{children}
7878
</h3>
7979
);

src/components/Post/PostDetail/PostHeader.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ const PostHeader = ({ postMetaData }: Props) => {
2828
'font-bold',
2929
'text-[3em]',
3030
'leading-[1.3]',
31-
'mt-[1em]'
31+
'mt-[1em]',
32+
'post-title'
3233
)}
3334
>
3435
{postMetaData.title}

src/components/Post/PostDetail/PostNavbar.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ const PostNavbar = ({ category = 'posts' }: Props) => {
9898
<ul className={classNames('max-h-[280px]', 'overflow-auto')}>
9999
{headings.map((heading) => (
100100
<li
101-
key={heading.textContent}
101+
key={`${heading.textContent}-${heading.dataset.index}`}
102102
className={classNames(
103103
'w-full',
104104
'px-4',
@@ -116,7 +116,9 @@ const PostNavbar = ({ category = 'posts' }: Props) => {
116116
>
117117
<a
118118
className={classNames('hover:underline')}
119-
href={`#${setElementId(heading.textContent)}`}
119+
href={`#${setElementId(heading.textContent)}-${
120+
heading.dataset.index
121+
}`}
120122
onClick={() => {
121123
setIsOpen(false);
122124
}}

0 commit comments

Comments
 (0)