[๋ฆฌ์•กํŠธ] ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” ์ ์šฉํ•˜๊ธฐ (ํ™”๋ฉด ๊ตฌ์„ฑ ๊ตฌํ˜„)

2025. 8. 9. 22:25ใ†React

๋ณ‘์› ์˜ˆ์•ฝ ๋ฐ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜ ํ”Œ๋žซํผ ํ”„๋กœ์ ํŠธ์—์„œ ๋กœ๊ทธ์ธ, ํšŒ์›๊ฐ€์ž…์„ ์ œ์™ธํ•œ ๋ชจ๋“  ํŽ˜์ด์ง€์— ์ ์šฉ๋  ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” ๊ฐœ๋ฐœ์„ ๋‹ด๋‹นํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ธ€์—์„œ๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”์˜ ์„ค๊ณ„๋ถ€ํ„ฐ ๊ตฌํ˜„, ๊ทธ๋ฆฌ๊ณ  ๋ฌธ์ œ ํ•ด๊ฒฐ ๊ณผ์ •์„ ์ •๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค. 

 

DocQ ํ”„๋กœ์ ํŠธ GitHub

 

DocQProject

DocQProject has 2 repositories available. Follow their code on GitHub.

github.com

 


๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” ์„ค๊ณ„

๐ŸŽจ UI ์„ค๊ณ„

  • ๋งˆ์šฐ์Šค๋ฅผ ๋ฉ”๋‰ด ์œ„์— ์˜ฌ๋ฆฌ๋ฉด ์ƒ‰์ƒ์ด ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.
  • ์„œ๋ธŒ ๋ฉ”๋‰ด๊ฐ€ ๋“œ๋กญ๋‹ค์šด ํ˜•ํƒœ๋กœ ๋‚˜ํƒ€๋‚˜๋„๋ก ์„ค๊ณ„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ๋ฉ”์ธ(Home)๊ณผ ๊ฒŒ์‹œํŒ์€ ํ•˜์œ„ ํ•ญ๋ชฉ์ด ์—†์œผ๋ฏ€๋กœ ์„œ๋ธŒ ๋ฉ”๋‰ด๋ฅผ ๋น„์›๋‹ˆ๋‹ค.

 


๐Ÿ“ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” ์œ„์น˜

  • ํŽ˜์ด์ง€ ์ƒ๋‹จ์— ๊ณ ์ •๋ฉ๋‹ˆ๋‹ค.
  • <header> ํƒœ๊ทธ๋กœ ์˜์—ญ ์ •์˜ํ•˜์˜€์Šต๋‹ˆ๋‹ค. 

๐Ÿ’ก <head>์™€ <header> ์ฐจ์ด

๋”๋ณด๊ธฐ

๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” ๊ธฐ์ดˆ ๊ตฌ์„ฑ

์ฃผ์š” ํ•ญ๋ชฉ

  • ๋กœ๊ณ 
  • ๋ฉ”์ธ(Home)
  • ๊ฒŒ์‹œํŒ
  • ๋ณ‘์›
  • ๋งˆ์ดํŽ˜์ด์ง€
  • ๊ฒ€์ƒ‰ ์ž…๋ ฅ์ฐฝ๊ณผ ๊ฒ€์ƒ‰ ๋ฒ„ํŠผ


๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” ๊ตฌํ˜„

๋กœ๊ณ  ๋„ฃ๊ธฐ

<Link to="/">
  <img
    src="src/assets/Doc-Q.png"
    className="w-20 h-20 me-20"
    style={{ clipPath: "inset(20% 0 20% 0)" }}
    alt="icon"
  />
</Link>
  • ๋กœ๊ณ  ํด๋ฆญ ์‹œ ๋ฉ”์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™๋ฉ๋‹ˆ๋‹ค. 

๋ฉ”์ธ ๋ฉ”๋‰ด ๋งŒ๋“ค๊ธฐ

๐Ÿ’ก ์„œ๋ธŒ ๋ฉ”๋‰ด URL์€ ์•„์ง ์—†์–ด ๋ฐฐ์—ด๋กœ๋งŒ ํ‘œ์‹œํ•˜์˜€์Šต๋‹ˆ๋‹ค. 

 

NavbarMenu.jsx

function NavbarMenu({ url, menuName, subMenu = [] }) {
    return (
        <li>
            <Link to={url}>
                <span className="font-bold text-2xl px-10 py-10">{menuName}</span>
            </Link>
        </li>
    );
}
 
 

NavigationBar.jsx

<div className="flex flex-1 flex-row h-full">
    <ul className="flex flex-row h-full">
        <NavbarMenu url="/" menuName="๋ฉ”์ธ" />
        <NavbarMenu url="/board" menuName="๊ฒŒ์‹œํŒ" />
        <NavbarMenu
            url="/mypage"
            menuName="๋งˆ์ด ํŽ˜์ด์ง€"
            subMenu={["๋‚ด ์ •๋ณด", "๋‚ด ์˜ˆ์•ฝ", "๋‚ด ๋ณ‘์›"]}
        />
        <NavbarMenu
            url="/"
            menuName="๋ณ‘์›"
            subMenu={["์น˜๊ณผ", "์•ˆ๊ณผ", "์ด๋น„์ธํ›„๊ณผ", "ํ”ผ๋ถ€๊ณผ"]} 
        />
    </ul>
</div>
 

๊ฒ€์ƒ‰ ๋งŒ๋“ค๊ธฐ

๐Ÿ’ก ์•„์ง ๋ฐฑ์—”๋“œ ์—ฐ๋™์ด ์•ˆ ๋˜์–ด submit ๊ธฐ๋Šฅ์€ ๊ตฌํ˜„๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. 

<div className="flex flex-row">
    <form role="search" className="flex max-w-md px-5">
        <input
            type="search"
            placeholder="๊ฒ€์ƒ‰..."
            aria-label="Search"
            className="w-full px-3 py-2 border border-gray-300 rounded"
        />
    </form>
    <button className="px-4 py-2 text-white bg-black rounded">
        ๊ฒ€์ƒ‰
    </button>
</div>

๋งˆ์šฐ์Šค ์˜ค๋ฒ„ ํšจ๊ณผ

๐Ÿ“— [Javascript] ๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ(event) ์ข…๋ฅ˜

 

[Javascript] ๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ(event) ์ข…๋ฅ˜

๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ์˜ ์ข…๋ฅ˜๋ฅผ ์•Œ์•„๋ณด๊ณ , ๊ฐ ์ด๋ฒคํŠธ๋“ค์ด ์–ธ์ œ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ์ •๋ฆฌํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค. 0. ๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ์˜ ์ข…๋ฅ˜ 1. click, mousedown, mouseup 2. dblclick 3. mousemove 4. mouseover, mouseout 5. mouseenter, mous

hianna.tistory.com

 

onMouseEnter์™€ onMouseLeave๋ฅผ ํ†ตํ•ด ๋งˆ์šฐ์Šค ์˜ค๋ฒ„ ์‹œ ์ƒ‰์ƒ ๋ณ€๊ฒฝ๋˜๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค. 

function NavbarMenu({ url, menuName, isSubMenu = false}) {
    const [isActiveSection, setIsActiveSection] = useState(false);

    return (
        <li
            onMouseEnter={() => setIsActiveSection(true)}
            onMouseLeave={() => setIsActiveSection(false)}
        >
            <Link to={url}>
                <span
                    className={`font-bold text-2xl px-10 py-10 transition-colors ${isActiveSection ? "text-blue-600 border-b-4 border-blue-600 pb-4" : ""}`}
                >
                    {menuName}
                </span>
            </Link>
        </li>
    );
}
 

โš ๏ธ ๊นœ๋นก๊ฑฐ๋ฆผ ๋ฌธ์ œ

  • border-b-4์™€ pb-4๊ฐ€ ํ•จ๊ป˜ ์ ์šฉ๋˜์–ด ๋†’์ด๊ฐ€ ๋ณ€ํ•ด ๋งˆ์šฐ์Šค ๊ฒฝ๊ณ„๋ฉด์—์„œ ๊นœ๋นก๊ฑฐ๋ฆผ ๋ฐœ์ƒํ•˜์˜€์Šต๋‹ˆ๋‹ค. 
  • pb-4 ์ œ๊ฑฐ + border-transparent ์‚ฌ์šฉ โžก๏ธ ๋†’์ด ๋ณ€ํ™” ์—†์ด ์ƒ‰์ƒ๋งŒ ๋ณ€๊ฒฝ

์ˆ˜์ • ์ฝ”๋“œ

 
<Link to={url} className="">
    <span
        className={`
            font-bold text-2xl px-10 py-3 border-b-4 transition-colors 
            ${isActiveSection ? "text-blue-600 border-blue-600" : "border-transparent"}
        `}
    >
        {menuName}
    </span>
</Link>

ํ•˜์œ„ ๋ฉ”๋‰ด(์„œ๋ธŒ ๋ฉ”๋‰ด) ๋“œ๋กญ๋‹ค์šด

  • ๋ถ€๋ชจ ๋ฉ”๋‰ด: relative
  • ์„œ๋ธŒ ๋ฉ”๋‰ด: absolute
  • ๋งˆ์šฐ์Šค ์˜ค๋ฒ„ ์‹œ ํ•˜์œ„ ๋ฉ”๋‰ด๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

function NavbarMenu({ url, menuName, subMenu = [] }) {
  const [isActiveSection, setIsActiveSection] = useState(false);
  const isSubMenuActive = isActiveSection && subMenu.length !== 0;

  return (
    <li
      className={`flex items-center h-full ${isSubMenuActive ? "relative" : ""}`}
      onMouseEnter={() => setIsActiveSection(true)}
      onMouseLeave={() => setIsActiveSection(false)}
    >
      <Link to={url}>
        <span
          className={`font-bold text-2xl px-10 py-3 border-b-4 transition-colors ${
            isActiveSection ? "text-blue-600 border-blue-600" : "border-transparent"
          }`}
        >
          {menuName}
        </span>
      </Link>

      {isSubMenuActive && (
        <ul className="absolute top-full left-0 flex flex-col justify-center items-center bg-white shadow w-full">
          {subMenu.map((item, index) => (
            <li key={index} className="font-bold my-5 mx-3">
              {item}
            </li>
          ))}
        </ul>
      )}
    </li>
  );
}

๋ณด์™„์  ๋ฐ ํ–ฅํ›„ ๊ณ„ํš

์ด๋ฒˆ ๊ตฌํ˜„์—์„œ๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”์˜ ์ „๋ฐ˜์ ์ธ ๊ตฌ์กฐ ์„ค๊ณ„ โžก๏ธ ์‹œ๋งจํ‹ฑ ํƒœ๊ทธ ์ ์šฉ โžก๏ธ hover๊นŒ์ง€ ๊ตฌํ˜„ ์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค.
๋‹ค๋งŒ ์„œ๋ธŒ ๋ฉ”๋‰ด ํ•ญ๋ชฉ์€ ํ˜„์žฌ ํŽ˜์ด์ง€ ์ด๋™ ๋ถˆ๊ฐ€, ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ๋„ UI๋งŒ ๊ตฌํ˜„๋œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.

 

์•ž์œผ๋กœ ๊ฐœ์„ ํ•  ์ 

  • ๋ฐฑ์—”๋“œ ์—ฐ๋™
    • ์„œ๋ฒ„์—์„œ ์„œ๋ธŒ ๋ฉ”๋‰ด ๋ฐ์ดํ„ฐ ๋™์  ๋ Œ๋”๋ง
    • ์„œ๋ธŒ ๋ฉ”๋‰ด ํด๋ฆญ ์‹œ ํ•ด๋‹น ํŽ˜์ด์ง€๋กœ ์ด๋™ ๊ฐ€๋Šฅํ•˜๋„๋ก ๋ผ์šฐํŒ… ์„ค์ •
  • ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ
    • ๊ฒ€์ƒ‰์–ด ์ž…๋ ฅ ํ›„ ๋ฒ„ํŠผ ํด๋ฆญ ๋˜๋Š” Enter ์‹œ /search ํŽ˜์ด์ง€๋กœ ์ด๋™
    • ์„œ๋ฒ„์—์„œ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋ฐ›์•„ ๋ณ‘์› ๋ฆฌ์ŠคํŠธ ์ถœ๋ ฅ