프론트엔드/Component

[Component] 사이드바 컴포넌트(MUI + styled-components + Zustand)

순코딩 2024. 12. 26. 17:11

 

 

import { SidebarStoreType } from "@/types/store/sidebar.type";
import { create } from "zustand";

export const useSidebarStore = create<SidebarStoreType>((set) => ({
  isOpen: false,
  items: [
    { text: "제로 칼로리", isSelect: false, query: "zero_calories" },
    { text: "로우 칼로리", isSelect: false, query: "low_calories" },
    { text: "제로 슈가", isSelect: false, query: "zero_sugar" },
    { text: "로우 슈가", isSelect: false, query: "low_sugar" },
  ],
  setItem: (index) =>
    set((state) => ({
      items: state.items.map((el, i) => (i === index ? { ...el, isSelect: true } : { ...el, isSelect: false })),
    })),
  open: () => set((state) => ({ ...state, isOpen: true })),
  close: () => set((state) => ({ ...state, isOpen: false })),
}));

사이드바 상태 스토어

 

export type SidebarStoreType = {
  isOpen: boolean;
  items: item[];
  setItem: (index : number) => void;
  open: () => void;
  close: () => void;
};

type item = {
  text:string;
  isSelect:boolean;
  query:string;
};

사이드바 상태 타입

 

"use client";

import * as React from "react";
import SwipeableDrawer from "@mui/material/SwipeableDrawer";
import Button from "@mui/material/Button";
import { useSidebarStore } from "@/store/sidebarStore";
import SidebarItem from "./SidebarItem";
import styled from "styled-components";

const Sidebar = () => {
  const { items, isOpen, open, close } = useSidebarStore();

  const RenderMenuArr = items.map((el, idx) => {
    return <SidebarItem key={idx} index={idx} text={el.text} isSelect={el.isSelect} query={el.query} />;
  });

  return (
    <>
      <Button onClick={() => open()}>사이드바 버튼</Button>
      <Container open={isOpen} onClose={close} onOpen={open}>
        {RenderMenuArr}
      </Container>
    </>
  );
};

export default Sidebar;

const Container = styled(SwipeableDrawer)`
  /* 사이드바 컨테이너 선택자 */
  & > .MuiPaper-root {
    background-color: white;
  }
`;

사이드바 컴포넌트

 

"use client";

import { useProductStore } from "@/store";
import { useSidebarStore } from "@/store/sidebarStore";
import styled from "styled-components";

type PropsType = {
  index : number;
  text: string;
  isSelect: boolean;
  query: string;
};

const SidebarItem = ({ index, text, isSelect, query }: PropsType) => {
  const setMajorCategory = useProductStore((state) => state.setMajorCategory);
  const setItem = useSidebarStore((state)=> state.setItem);

  function handleClick() {
    setMajorCategory(query);
    setItem(index);
  }

  return (
    <Container onClick={handleClick} $isSelect={isSelect}>
      {text}
    </Container>
  );
};

export default SidebarItem;

////////////////////////////// 스타일드 컴포넌트

type ContainerType = {
  $isSelect: boolean;
};

const Container = styled.div<ContainerType>`
  width: 150px;
  height: 50px;
  display: flex;
  align-items: center;
  padding: 0px 12px;
  font-size: 16px;
  background-color: ${({ $isSelect }) => ($isSelect === true ? "white" : "#F6F7F9")};
  color: ${({ $isSelect }) => ($isSelect === true ? "var(--black)" : "var(--gray)")};
`;

사이드바 아이템 컴포넌트