Skip to content

Commit

Permalink
[feat] 하단 내비게이션 TabBar : svgr cli 설정, 탭이 선택되면 icon 색 변화
Browse files Browse the repository at this point in the history
  • Loading branch information
devchaen committed Mar 14, 2024
1 parent 5ccb317 commit a38fcd4
Show file tree
Hide file tree
Showing 10 changed files with 252 additions and 39 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"mock": "npx tsx watch ./src/mocks/http.ts"
"mock": "npx tsx watch ./src/mocks/http.ts",
"icons": "npx @svgr/cli --template ./svgr.template.cjs --ext tsx --out-dir src/components/icons -- src/assets/icons"
},
"dependencies": {
"@mswjs/http-middleware": "^0.9.2",
Expand Down
119 changes: 83 additions & 36 deletions src/components/Tabbar.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,95 @@
import { Badge, TabBar } from 'antd-mobile';
import { useCallback, useEffect, useState } from 'react';
import HomeIcon from '@/assets/icons/home.svg?react';
import FeedsIcon from '@/assets/icons/feed.svg?react';
import NewPostIcon from '@/assets/icons/newPost.svg?react';
import ChatIcon from '@/assets/icons/message.svg?react';
import MypageIcon from '@/assets/icons/mypage.svg?react';
import { useLocation, useNavigate } from 'react-router-dom';

const tabs = [
{
key: 'home',
title: '홈',
icon: <HomeIcon />,
},
{
key: 'feeds',
title: '피드',
icon: <FeedsIcon />,
},
{
key: 'newPost',
title: '새 게시물',
icon: <NewPostIcon />,
},
{
key: 'chat',
title: '메시지',
icon: <ChatIcon />,
badge: Badge.dot,
},
{
key: 'user',
title: '마이페이지',
icon: <MypageIcon />,
},
];
import {
FeedIcon,
HomeIcon,
MessageIcon,
MypageIcon,
NewPostIcon,
} from './icons';

const Tabbar = () => {
const { pathname } = useLocation();
const navigate = useNavigate();
const [activeKey, setActiveKey] = useState<string>('');
const userId = '1';

const tabs = [
{
key: 'home',
title: '홈',
icon: (
<HomeIcon
mainColor={
activeKey === 'home' ? 'var(--accent)' : 'var(--secondary)'
}
/>
),
},
{
key: 'feeds',
title: '피드',
icon: (
<FeedIcon
mainColor={
activeKey === 'feeds' ? 'var(--accent)' : 'var(--secondary)'
}
subColor={
activeKey === 'feeds'
? 'var(--accent-foreground)'
: 'var(--secondary-foreground)'
}
/>
),
},
{
key: 'newPost',
title: '새 게시물',
icon: (
<NewPostIcon
mainColor={
activeKey === 'newPost' ? 'var(--accent)' : 'var(--secondary)'
}
subColor={
activeKey === 'newPost'
? 'var(--accent-foreground)'
: 'var(--secondary-foreground)'
}
/>
),
},
{
key: 'chat',
title: '메시지',
icon: (
<MessageIcon
mainColor={activeKey === 'chat' ? 'var(--accent)' : 'var(--secondary'}
subColor={
activeKey === 'chat'
? 'var(--accent-foreground)'
: 'var(--secondary-foreground'
}
/>
),
badge: Badge.dot,
},
{
key: 'user',
title: '마이페이지',
icon: (
<MypageIcon
mainColor={activeKey === 'user' ? 'var(--accent)' : 'var(--secondary'}
subColor={
activeKey === 'user'
? 'var(--accent-foreground)'
: 'var(--secondary-foreground'
}
/>
),
},
];

/*
주소창으로 접속 시 or 새로고침 : pathname으로 tab 자동 선택 (activeKey값 설정)
*/
Expand All @@ -63,10 +111,9 @@ const Tabbar = () => {
}
}, []);

// 최초 렌더링 시에만 syncTabWithPath 함수 실행
useEffect(() => {
syncTabWithPath(pathname);
}, []);
}, [pathname]);

/*
탭 Item 선택 시 해당 화면으로 Navigate
Expand Down
29 changes: 29 additions & 0 deletions src/components/icons/Feed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { SVGProps } from 'react';

interface SvgFeedProps extends SVGProps<SVGSVGElement> {
mainColor: string;
subColor: string;
}

const SvgFeed = ({ mainColor, subColor, ...props }: SvgFeedProps) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
fill="none"
{...props}
>
<path
fill={mainColor}
d="M3 4v16a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2"
/>
<path
stroke={subColor}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.25}
d="M7 7h10M7 17.002h10M7 12h10"
/>
</svg>
);
export default SvgFeed;
23 changes: 23 additions & 0 deletions src/components/icons/Home.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { SVGProps } from 'react';

interface SvgHomeProps extends SVGProps<SVGSVGElement> {
mainColor: string;
}

const SvgHome = ({ mainColor, ...props }: SvgHomeProps) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
fill="none"
{...props}
>
<path
fill={mainColor}
stroke={mainColor}
strokeWidth={1.25}
d="m2.766 10.188 9-7.2a.375.375 0 0 1 .468 0l9 7.2c.09.071.141.179.141.293V21a.375.375 0 0 1-.375.375h-4.5a.375.375 0 0 1-.375-.375v-6c0-.898-.727-1.625-1.625-1.625h-5c-.897 0-1.625.727-1.625 1.625v6a.375.375 0 0 1-.375.375H3A.375.375 0 0 1 2.625 21V10.48c0-.113.052-.221.14-.292Z"
/>
</svg>
);
export default SvgHome;
25 changes: 25 additions & 0 deletions src/components/icons/Message.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { SVGProps } from 'react';

interface SvgMessageProps extends SVGProps<SVGSVGElement> {
mainColor: string;
subColor: string;
}

const SvgMessage = ({ mainColor, subColor, ...props }: SvgMessageProps) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
fill="none"
{...props}
>
<rect width={15} height={10} x={2} y={3.512} fill={subColor} rx={5} />
<path
fill={mainColor}
fillRule="evenodd"
d="M7 14.512a5 5 0 0 1 5-5h5a5 5 0 0 1 3.484 8.587c.257.837.734 1.5 1.146 1.992.14.166.025.415-.19.395-1.209-.111-2.28-.571-3.157-1.14q-.617.165-1.283.166h-5a5 5 0 0 1-5-5m8.5 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2m-7-1a1 1 0 1 1-2 0 1 1 0 0 1 2 0"
clipRule="evenodd"
/>
</svg>
);
export default SvgMessage;
38 changes: 38 additions & 0 deletions src/components/icons/Mypage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { SVGProps } from 'react';

interface SvgMypageProps extends SVGProps<SVGSVGElement> {
mainColor: string;
subColor: string;
}

const SvgMypage = ({ mainColor, subColor, ...props }: SvgMypageProps) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
fill="none"
{...props}
>
<path
fill={subColor}
d="m9.525 15.94.61-2.408 1.828-1.307 1.829 1.307.61 2.407a3.138 3.138 0 0 1-4.877 0"
/>
<path
fill={mainColor}
d="M7.063 9.216c-1.828-4.814 2.05-7.606 4.811-7.05 2.096-.462 3.566.024 4.818 1.634 1.25 1.61.61 4.212 0 5.416-2.06.076-2.519-1.14-3.01-1.806-1.444 2.408-5.222 2.175-6.619 1.806"
/>
<path
fill={subColor}
d="M11.978 14.705c-3.806 0-4.36-4.012-4.162-6.018 1.189.2 3.924.12 5.35-1.805.595.602 2.022 1.805 2.974 1.805.198 2.006-.357 6.018-4.162 6.018"
/>
<path
fill={subColor}
d="M7.154 9.107c.254-.096.527-.135.798-.113l.473 3.497a1.84 1.84 0 0 1-1.565-.154 1.82 1.82 0 0 1-.862-1.304 1.79 1.79 0 0 1 .485-1.483c.187-.195.416-.347.67-.443M16.847 9.107a1.8 1.8 0 0 0-.799-.113l-.473 3.497a1.84 1.84 0 0 0 1.565-.154 1.82 1.82 0 0 0 .862-1.304 1.79 1.79 0 0 0-.485-1.483 1.8 1.8 0 0 0-.67-.443"
/>
<path
fill={mainColor}
d="M4 18.85v1.636C4 21.322 4.672 22 5.5 22H12v-5.047c-1.367 0-2.102-.86-2.39-1.32a.27.27 0 0 0-.319-.118l-3.966 1.434A2.02 2.02 0 0 0 4 18.85M20 18.85v1.636c0 .836-.672 1.514-1.5 1.514H12v-5.047c1.367 0 2.102-.86 2.39-1.32a.27.27 0 0 1 .319-.118l3.966 1.434A2.02 2.02 0 0 1 20 18.85"
/>
</svg>
);
export default SvgMypage;
29 changes: 29 additions & 0 deletions src/components/icons/NewPost.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { SVGProps } from 'react';

interface SvgNewPostProps extends SVGProps<SVGSVGElement> {
mainColor: string;
subColor: string;
}

const SvgNewPost = ({ mainColor, subColor, ...props }: SvgNewPostProps) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
fill="none"
{...props}
>
<path
fill={mainColor}
d="M3 4v16a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2"
/>
<path
stroke={subColor}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.25}
d="M12 8v8M8 12h8"
/>
</svg>
);
export default SvgNewPost;
5 changes: 5 additions & 0 deletions src/components/icons/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { default as FeedIcon } from './Feed';
export { default as HomeIcon } from './Home';
export { default as MessageIcon } from './Message';
export { default as MypageIcon } from './Mypage';
export { default as NewPostIcon } from './NewPost';
4 changes: 2 additions & 2 deletions src/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
--primary: #000000;
--primary-foreground: #909396;

--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--secondary: #aaaeb1;
--secondary-foreground: #e2e6e9;

--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
Expand Down
16 changes: 16 additions & 0 deletions svgr.template.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const template = (variables, { tpl }) => {
return tpl`
import React from 'react';
${variables.imports};
${variables.interfaces};
const ${variables.componentName} = (${variables.props}) => (
${variables.jsx}
);
${variables.exports};
`;
};

module.exports = template;

0 comments on commit a38fcd4

Please sign in to comment.