- Published on
๐ ์ปฌ๋ฌ๋ฆฌ์คํธ ํ๋ก์ ํธ #7 drawer ๋ง๋ค๊ณ pallete ์ปดํฌ๋ํธ ๋ถ๋ฆฌ
- ๊ธ์ด์ด
๐ ๋ชฉ์ฐจ
๐๐ป
- drawer ๋ง๋ค๊ธฐ
- pallete ์ปดํฌ๋ํธ ๋ถ๋ฆฌ
1. drawer ์ฌ์ฉ๋ฒ ์ตํ๊ธฐ - ์ฌ๋กฏ,์น ๋๋ฐ ์ฐ๋ ๋ฒ
Drawer.tsx
๋ฅผ ๋ง๋ค์ด์ค๋๋ค.
1-1. daisy ui๋ก drawer์ ๋ง๋ค๊ธฐ ์ํด
import * as React from 'react'
import './Nav.css'
//Drawer์ ์ฌ๋ ์คํ ๋ฒํผ์ ๋ฐ๋ก ๋ง๋ค์ด์ค๋๋ค.
//์ ๋ ์ด๋ฏธ์ง๋ฅผ ์ธ ๊ฑฐ๋ผ label์ฌ์ด์ img๋ฅผ ๋ฃ์ด์ฃผ์์ด์.
export function DrawerOpenButton() {
return (
<label role="button" htmlFor="my-drawer" className="drawer-button">
<img src="src/img/icons8-menu.svg"></img>
</label>
)
}
//์ฌ๊ธฐ Drawer()์์ ๋ค์ด์๋ {children}์ด
//Drawer์ ์ด์์ ๋ ๋ค์ด๊ฐ ๋ด์ฉ๋ค์
๋๋ค.
function Drawer({ children }) {
return (
<div className="drawer">
<input id="my-drawer" type="checkbox" className="drawer-toggle" />
{/* drawer-content์์ children์ ๋ฃ์ผ๋ฉด ๋๋ค. */}
<div className="drawer-content">{children}</div>
<div className="drawer-side">
<label htmlFor="my-drawer" className="drawer-overlay"></label>
<ul className="menu p-4 overflow-y-auto w-80 bg-base-100 text-base-content mb-0">
<li>
<a>Sidebar Item 1</a>
</li>
<li>
<a>Sidebar Item 2</a>
</li>
</ul>
</div>
</div>
)
}
export default Drawer
1-2. ์ด๋ ๊ฒ 'Drawer.tsx'๋ฅผ ๋ง๋ค์์ผ๋ฉด, ์ด ์ปดํฌ๋ํธ๋ฅผ ๋ฃ์ ํ์ด์ง๋ฅผ ๊ณจ๋ผ์ผํ์ฃ .
์ ์ ๊ฒฝ์ฐ๋ ์์ ๋ค๋น๊ฒ์ด์
๊น์ง๋ ๋ฎ๊ธฐ๋ฅผ ํฌ๋งํ๊ธฐ ๋๋ฌธ์ 'Index.tsx'์ import
ํ์ต๋๋ค.
import Drawer from './Drawer'
์ด๋ ๊ฒ import
๋ฅผ ํด์ฃผ์์ผ๋ฉด,
Drawer๊ฐ ์ด๋ฆด ๋ ๊ฐ๋ ค์ง ์์๋ค์ ๋ชจ๋ ๊ฐ์ธ๋๋ก <Drawer><Drawer />
๋ฅผ ๋ฃ์ด์ค๋๋ค.
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<Drawer>
<Nav />
<Routes>
<Route path="/" element={<TestForm />} />
<Route path="/login/*" element={<Login />} />
{/* ์๋จ์ ์์นํ๋ ๋ผ์ฐํธ๋ค์ ๊ท์น์ ๋ชจ๋ ํ์ธ, ์ผ์นํ๋ ๋ผ์ฐํธ๊ฐ ์๋๊ฒฝ์ฐ ์ฒ๋ฆฌ */}
<Route path="*" element={<Notfound />}></Route>
</Routes>
</Drawer>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
)
์ด๋ ๊ฒ ํ๋ฉด Drawer ๋ง๋ค๊ธฐ๋ ๋!
2. ์ด๋ฒ์ pallete๋ฅผ ์ปดํฌ๋ํธ๋ก ๋ถ๋ฆฌํฉ๋๋ค.
rfce
๋ก ๊ธฐ๋ณธ ํ์ ๋ง๋ค์ด์ค๋๋ค.
2-1. ๋จผ์ 'Pallete.tsx'๋ผ๋ ํ์ผ์ ๋ง๋ค๊ณ ๋ช
๋ น์ด Tooltip.provider
๋ฅผ pallete table ์์ ๊ฐ์ธ๊ณ ๊ทธ ์์ ์๋ ๋ชจ๋ ์์๋ฅผ ์ฎ๊ฒจ์ค๋๋ค..
2-2.pallete์์ ์ด ๋ ๋ฏธ๋ฆฌ ์ง์ ํด๋์ WHITEHEX์ colors ๋ฐฐ์ด ๋ฑ Pallete์ ํ์ํ ์์๋ค๋ ํจ๊ป ์ฎ๊ฒจ์ค๋๋ค.
import React from 'react'
import * as Tabs from '@radix-ui/react-tabs'
import * as Tooltip from '@radix-ui/react-tooltip'
import allPallete from './pallete.json'
// ["base", "deep"]
const palleteTypes = Object.keys(allPallete)
const BOX_COUNT = 10
const WHITE_HEX = '#ffffff'
function Pallete() {
const [colors, setColors] = React.useState(Array(BOX_COUNT).fill(WHITE_HEX)) // ๋ฌธ์์ด
//6๋ฒ - addSelected ํจ์๋ฅผ ๋ง๋ค์ด
function addSelected(hex: string) {
setColors((old) => {
// findIndex๋ ๋ฐฐ์ด์ ๊ฐ ์ค์์ ์กฐ๊ฑด์ ๋ง๋ ๊ฐ์ด ์๋ ์ฒซ ๋ฒ์งธ index๋ฅผ ์ฐพ๋๋ค!
// hex ์ค์์ hex์ ์์ด white์ธ ์ฒซ๋ฒ์งธ index๋ฅผ ์ฐพ์๋ธ๋ค.
const firstWhiteIndex = old.findIndex((hex) => hex === WHITE_HEX)
if (firstWhiteIndex === -1) {
// ์ธ๋ฑ์ค๋ฅผ ๋ชป ์ฐพ์ผ๋ฉด! -1์ ๋ฐํ
return old // ์๋ colors๋ฅผ ๊ทธ๋๋ก ๋ฐํ... ๋ ์ฑ์ธ ํ์์นธ์ด ์์ผ๋ฏ๋ก!
}
// ์ด๋ฏธ ๋ฐ๋ ์์ old๋๋ก ๋๋๊ณ
const copy = [...old]
// ์ฐพ์๋ธ ์ฒซ ๋ฒ์งธ ์ธ๋ฑ์ค์ hex๊ฐ์ ๋ฃ๋๋ค.
copy[firstWhiteIndex] = hex
return copy // newState !!!
})
}
//7๋ฒ - deleteSelected ํจ์๋ฅผ ๋ง๋ค์ด
function deleteSelected(targetIndex: number) {
setColors((old) => {
const copy = [...old]
// targetIndex์ ๊ฐ์ ํฐ์ ํฅ์ค๋ฅผ ๋ฃ๋๋ค.
copy[targetIndex] = WHITE_HEX
return copy // newState !!!
})
}
return (
<Tooltip.Provider delayDuration={800} skipDelayDuration={500}>
<input hidden type="text" name="colors" value={JSON.stringify(colors)} />
<table className="selectedContainer flex flex-row">
<tbody>
{/* 2๋ฒ - map์ ์จ์ ๋ฐฐ์ด์ ๊ฐ์ ํ๋ฉด์ ๋ฟ๋ ค์ค๋ค. */}
{/* https://beta.reactjs.org/learn/rendering-lists */}
<tr>
{/* 7.2๋ฒ - targetIndex๋ ์ฌ๊ธฐ์ index๋ฅผ ๋ฐ์์จ ๊ฐ์ด๋ค. */}
{colors.map((color, index) => (
// 3๋ฒ - ์คํ์ผ์ map์ผ๋ก ๋ฐ์์จ color ๋ฌธ์์ด ๊ฐ์ backgroundColor๋ก ์ง์ ํด์ค๋ค.
<td
key={`${color}-${index}`}
// ์ด๊ฒ ์ ํํ ์นธ์ index
onClick={() => deleteSelected(index)}
style={{
backgroundColor: color,
}}
>
{color}
</td>
))}
</tr>
</tbody>
</table>
<div id="pallete-box">
<Tabs.Root defaultValue={Object.keys(allPallete)[0]} orientation="horizontal">
<Tabs.List aria-label="select pallete type">
{/* ํ๋ ํธ์ ํ์
๋ง๋ค Tabs.Trigger๋ฅผ ๋ง๋ค์ด์ค๋ค*/}
{palleteTypes.map((value) => (
<Tabs.Trigger key={value} value={value} className="bg-yellow-200">
{value}
</Tabs.Trigger>
))}
</Tabs.List>
{/* ["base", "deep"]*/}
{/* ํ๋ ํธ์ ํ์
๋ง๋ค Tabs.Content๋ฅผ ๋ง๋ค์ด์ค๋ค*/}
{palleteTypes.map((value) => (
<Tabs.Content key={value} value={value}>
<div id="pallete" className="flex flex-row flex-wrap">
{/* 4๋ฒ - pallete๋ ๊ฐ์ด ์ฌ๋ฌ ๊ฐ์ด๋ฏ๋ก map์ ์ฌ์ฉํ๋ค. */}
{allPallete[value].map(({ hex, colorName }, index) => (
<Tooltip.Root>
<Tooltip.Trigger asChild>
<button
key={index}
onClick={() => addSelected(hex)}
className="roundButton"
style={{ backgroundColor: hex }}
>
{colorName}
</button>
</Tooltip.Trigger>
<Tooltip.Content className="tooltip-content">
{hex}
<Tooltip.Arrow className="tooltip-arrow" width="20" height="10" />
</Tooltip.Content>
</Tooltip.Root>
))}
</div>
</Tabs.Content>
))}
</Tabs.Root>
</div>
</Tooltip.Provider>
)
}
export default Pallete
์ด๋ ๊ฒ Pallete๋ฅผ ์ปดํฌ๋ํธ๋ก ๋ถ๋ฆฌํ๋ฉด TestForm.tsx
์ ์ฝ๋๊ฐ 130์ค์ด๋ ์ค์ด๋ค์ด ํจ์ฌ ๋ณด๊ธฐ ํธํด์ง๋๋ค.