โ ๋ฌธ์ ์
๐ก ์ฅ์
๋์์ธ ์์คํ ์ด๋ ์๋น์ค๋ฅผ ๋ง๋๋ ๋ฐ ์ฌ์ฉํ ๊ณตํต ์ปฌ๋ฌ, ์์ฒด, ์ธํฐ๋์ , ๊ฐ์ข ์ ์ฑ ๋ฐ ๊ท์ ์ ๊ดํ ๋ชจ๋ ์ปดํฌ๋ํธ๋ฅผ ์ ๋ฆฌํด๋์ ๊ฒ์ด๋ฉฐ ๋ถํ์ํ ์ปค๋ฎค๋์ผ์ด์ ์ ์์ ๊ธฐ ์ํด ์ฒด๊ณ์ ์ผ๋ก ์ ๋ฆฌํ ์์คํ ์ ๋งํ๋ค.
๐ก ๋์์ธ ์์คํ ์ ํน์ง
๐ ๋ง์ ๊ธฐ์
๋ค์ด ์ฌ์ฉํ๊ณ ์๋ Tool
๐ ์คํ ๋ฆฌ๋ถ(Storybook): UI ์ปดํฌ๋ํธ ๊ฐ๋ฐ๊ณผ ์๋์ผ๋ก ๋ฌธ์๋ฅผ ์์ฑํ ๋ ์ฌ์ฉํฉ๋๋ค.
โ๏ธ ๋ฆฌ์กํธ(React): ์ ์ธ ์ค์ฌ ์ปดํฌ๋ํธ UI(create-react-app)๋ฅผ ์ฌ์ฉํฉ๋๋ค.
๐
์คํ์ผ ์ปดํฌ๋ํธ(Styled-components): ์ปดํฌ๋ํธ ๋จ์์ ์คํ์ผ๋ง์ ์ฌ์ฉํฉ๋๋ค.
โจ ํ๋ฆฌํฐ์ด(Prettier): ์๋ํ๋ ์ฝ๋ ํฌ๋งทํ
์ ์ฌ์ฉํฉ๋๋ค.
Modal CSS
Modal ๋ฒํผ ๊ธฐ๋ฅ ๊ตฌํ
Modal ๋ฒํผ ๊ธฐ๋ฅ ๊ตฌํ ์ฝ๋
export const Modal = () => { const [isOpen, setIsOpen] = useState(false); const openModalHandler = () => { // TODO : isOpen์ ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ ๋ฉ์๋๋ฅผ ๊ตฌํํฉ๋๋ค. setIsOpen(!isOpen) }; return ( <> <ModalContainer onClick={openModalHandler}> {/* ์ฐฝ๋ฐ ํด๋ฆญํ ๊ฒฝ์ฐ Modal์ฐฝ ๋ซ๊ธฐ */} <ModalBtn // TODO : ํด๋ฆญํ๋ฉด Modal์ด ์ด๋ฆฐ ์ํ(isOpen)๋ฅผ boolean ํ์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ๋ฉ์๋๊ฐ ์คํ๋์ด์ผ ํฉ๋๋ค. onClick={openModalHandler} > {isOpen ? 'Opened!' : 'OpenModal'} {/* TODO : ์กฐ๊ฑด๋ถ ๋ ๋๋ง์ ํ์ฉํด์ Modal์ด ์ด๋ฆฐ ์ํ(isOpen์ด true์ธ ์ํ)์ผ ๋๋ ModalBtn์ ๋ด๋ถ ํ ์คํธ๊ฐ 'Opened!' ๋ก Modal์ด ๋ซํ ์ํ(isOpen์ด false์ธ ์ํ)์ผ ๋๋ ModalBtn ์ ๋ด๋ถ ํ ์คํธ๊ฐ 'Open Modal'์ด ๋๋๋ก ๊ตฌํํด์ผ ํฉ๋๋ค. */} </ModalBtn> {/* TODO : ์กฐ๊ฑด๋ถ ๋ ๋๋ง์ ํ์ฉํด์ Modal์ด ์ด๋ฆฐ ์ํ(isOpen์ด true์ธ ์ํ)์ผ ๋๋ง ๋ชจ๋ฌ์ฐฝ๊ณผ ๋ฐฐ๊ฒฝ์ด ๋ฐ ์ ์๊ฒ ๊ตฌํํด์ผ ํฉ๋๋ค. */} {isOpen === false ? null : <ModalBackdrop> <ModalView> <div className='desc'>๋ชจ๋ฌ ๋ด์ฉ์ด ๋ณด์ฌ์ง๋๋ค.</div> <Exitbtn onClick = {openModalHandler}>ํ์ธ</Exitbtn> </ModalView> </ModalBackdrop> } </ModalContainer> </> ); };
Toggle CSS
Toggle ๋ฒํผ ๊ธฐ๋ฅ ๊ตฌํ
<div className={`toggle-container ${isOn ? "toggle--checked" : ""}`} />
Toggle ๋ฒํผ ๊ธฐ๋ฅ ๊ตฌํ ์ฝ๋
export const Toggle = () => { const [isOn, setisOn] = useState(false); const toggleHandler = () => { // TODO : isOn์ ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ ๋ฉ์๋๋ฅผ ๊ตฌํํฉ๋๋ค. setisOn(!isOn) }; return ( <> <ToggleContainer // TODO : ํด๋ฆญํ๋ฉด ํ ๊ธ์ด ์ผ์ง ์ํ(isOn)๋ฅผ boolean ํ์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ๋ฉ์๋๊ฐ ์คํ๋์ด์ผ ํฉ๋๋ค. onClick={toggleHandler} > {/* TODO : ์๋์ div ์๋ฆฌ๋จผํธ 2๊ฐ๊ฐ ์์ต๋๋ค. ๊ฐ๊ฐ์ ํด๋์ค๋ฅผ 'toggle-container', 'toggle-circle' ๋ก ์ง์ ํ์ธ์. */} {/* TIP : Toggle Switch๊ฐ ON์ธ ์ํ์ผ ๊ฒฝ์ฐ์๋ง toggle--checked ํด๋์ค๋ฅผ div ์๋ฆฌ๋จผํธ 2๊ฐ์ ๋ชจ๋ ์ถ๊ฐํฉ๋๋ค. ์กฐ๊ฑด๋ถ ์คํ์ผ๋ง์ ํ์ฉํ์ธ์. */} <div className={`toggle-container ${isOn ? "toggle--checked" : null}`} /> <div className={`toggle-circle ${isOn ? "toggle--checked" : null}`} /> </ToggleContainer> {/* TODO : Desc ์ปดํฌ๋ํธ๋ฅผ ํ์ฉํด์ผ ํฉ๋๋ค. */} {/* TIP: Toggle Switch๊ฐ ON์ธ ์ํ์ผ ๊ฒฝ์ฐ์ Desc ์ปดํฌ๋ํธ ๋ด๋ถ์ ํ ์คํธ๋ฅผ 'Toggle Switch ON'์ผ๋ก, ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ 'Toggle Switch OFF'๊ฐ ๋ฉ๋๋ค. ์กฐ๊ฑด๋ถ ๋ ๋๋ง์ ํ์ฉํ์ธ์. */} {isOn === false ? <Desc> <div className='switch--Off'>Toggle Switch OFF</div></Desc> : <Desc> <div className='switch--On'>Toggle Switch ON</div></Desc> } </> ); };
Tab CSS
Tab ๊ธฐ๋ฅ ๊ตฌํ
Tab ๊ธฐ๋ฅ ๊ตฌํ ์ฝ๋
export const Tab = () => { // TIP: Tab Menu ์ค ํ์ฌ ์ด๋ค Tab์ด ์ ํ๋์ด ์๋์ง ํ์ธํ๊ธฐ ์ํ // currentTab ์ํ์ currentTab์ ๊ฐฑ์ ํ๋ ํจ์๊ฐ ์กด์ฌํด์ผ ํ๊ณ , ์ด๊ธฐ๊ฐ์ 0 ์ ๋๋ค. const [currentTab, setTab] = useState(0); const menuArr = [ { name: 'Tab1', content: 'Tab menu ONE' }, { name: 'Tab2', content: 'Tab menu TWO' }, { name: 'Tab3', content: 'Tab menu THREE' }, ]; const selectMenuHandler = (index) => { // TIP: parameter๋ก ํ์ฌ ์ ํํ ์ธ๋ฑ์ค ๊ฐ์ ์ ๋ฌํด์ผ ํ๋ฉฐ, ์ด๋ฒคํธ ๊ฐ์ฒด(event)๋ ์ฐ์ง ์์ต๋๋ค // TODO : ํด๋น ํจ์๊ฐ ์คํ๋๋ฉด ํ์ฌ ์ ํ๋ Tab Menu ๊ฐ ๊ฐฑ์ ๋๋๋ก ํจ์๋ฅผ ์์ฑํ์ธ์. setTab(index); }; return ( <> <div> <TabMenu> {/*TODO: ์๋ ํ๋์ฝ๋ฉ๋ ๋ด์ฉ ๋์ ์, map์ ์ด์ฉํ ๋ฐ๋ณต์ผ๋ก ์ฝ๋๋ฅผ ์์ ํฉ๋๋ค.*/} {/*TIP: li ์๋ฆฌ๋จผํธ์ class๋ช ์ ๊ฒฝ์ฐ ์ ํ๋ tab ์ 'submenu focused' ๊ฐ ๋๋ฉฐ, ๋๋จธ์ง 2๊ฐ์ tab์ 'submenu' ๊ฐ ๋ฉ๋๋ค.*/} {/* <li className="submenu">{menuArr[0].name}</li> <li className="submenu">{menuArr[1].name}</li> <li className="submenu">{menuArr[2].name}</li> */} {menuArr.map( (tap, index) => { return ( <li key = {index} className = {currentTab === index ? "submenu focused" : "submenu"} onClick = {() => selectMenuHandler(index)}>{tap.name}</li> ) })} </TabMenu> <Desc> {/*TODO: ์๋ ํ๋์ฝ๋ฉ๋ ๋ด์ฉ ๋์ ์, ํ์ฌ ์ ํ๋ ๋ฉ๋ด ๋ฐ๋ฅธ content๋ฅผ ํ์ํ์ธ์*/} <p>{menuArr[currentTab].content}</p> </Desc> </div> </> ); };
์ค๋์ ์ ๋ฒ์ ํผ๊ทธ๋ง๋ก ๋ง๋ค์๋ ๋ชจ๋ฌ, ํ ๊ธ, ํญ์ ์ฝ๋๋ก ๊ตฌํํด ๋ณด๋ ๊ณผ์ ๋ฅผ ์งํํ์๋ค. ๊ทธ๋ฆฌ๊ณ ์์ ๋ฐฐ์ด custom component๋ฅผ ํ์ฉํ์ฌ ์งํํ์๋ค. ๋๋ฆ ํ ๋งํ๊ณ , css ๋ถ๋ถ์ ์ฝ๊ฒ ํ ์ ์์ง๋ง ๊ธฐ๋ฅ ๊ตฌํ์์ ์ด์ง ์๊ทธ๋ํ๋ ๊ฒ ๊ฐ๋ค. ์์ง ๋ฒ ์ด๋ฏธ๋์ 1๊ฐ, ํ๊ทธ ๊ตฌํ๋ ํ์ง ์์๊ณ css ๋ถ๋ถ์์ ๋ง์์ ๋ค์ง ์๋ ๋ถ๋ถ๊ณผ ๊ฐ์ด๋ฐ ์ ๋ ฌ์ด ๋์ง ์๋ ๊ฒ์ ํด๊ฒฐํ๊ธฐ ์ํด ์ถ๊ฐ์ ์ผ๋ก ๋ด์ผ ๋ง๋ฌด๋ฆฌํ ์์ ์ด๋ค.