로고
nabongsun.shop

[nextJS] 포트폴리오 만들기(3)

1. 무엇을 할 것인가?

Content Filter 이런 동작을 원했는데, 해당 코드를 분석해보니 html과 jQuery를 이용해 해당 셈플 페이지를 만들었다...

그래도 다행인게 MixItUp 이라는 모듈을 누가 구현을 해놔서 그거만 잘 이용하면 만사OK였지만, 한국어 설명이 아무데도 없어서 결국엔 이글을 쓰게된 원동력이 되었다.

일단 필터와 앨범을 구현해보자.

components
│  ├─ Nav.tsx
│  └─ Container.tsx
data
├─ navlinks.ts
├─ (new)portfolios.ts
pages
├─ _app.tsx
├─ index.tsx
├─ (new)portfolio            // mypage/portfolio
│  └─ (new)index.tsx
public
├─ (new)portfolios           // 앨범 이미지 저장
│
styles
│
package.json

이제 새로생기는 디렉토리/파일은 (new)을 달아도 될것같다! a,b,c는 전부 삭제해주도록하자.

2. 추가작업?

  • pages안의 a,b,c를 삭제한다.
  • data/navilnks.ts를 수정한다.

data/navilnks.ts

const navlinks: { title: string; link: string }[] = [
  { title: "Home", link: "/" },
  { title: "포트폴리오", link: "/portfolio" },
];

export default navlinks;

  • public/portfolios에 img-1.jpg ~ img-12.jpg를 가져온다.

2.1 data

data/portfolios.ts

const portfolios: { imgsrc: string; filter: string[] }[] = [
  { imgsrc: "/portfolios/img-1.jpg", filter: ["all", "react", "nodejs"] },
  { imgsrc: "/portfolios/img-2.jpg", filter: ["all", "spring", "nodejs"] },
  { imgsrc: "/portfolios/img-3.jpg", filter: ["all", "nextjs"] },
  { imgsrc: "/portfolios/img-4.jpg", filter: ["all", "spring boot"] },
  { imgsrc: "/portfolios/img-5.jpg", filter: ["all", "react", "nodejs"] },
  { imgsrc: "/portfolios/img-6.jpg", filter: ["all", "nextjs"] },
  { imgsrc: "/portfolios/img-7.jpg", filter: ["all", "react", "nodejs"] },
  { imgsrc: "/portfolios/img-8.jpg", filter: ["all", "spring", "nodejs"] },
  { imgsrc: "/portfolios/img-9.jpg", filter: ["all", "nextjs", "spring boot"] },
  { imgsrc: "/portfolios/img-10.jpg", filter: ["all", "react", "nodejs"] },
  { imgsrc: "/portfolios/img-11.jpg", filter: ["all", "nextjs"] },
  { imgsrc: "/portfolios/img-12.jpg", filter: ["all", "react", "nodejs"] },
];

export var filters = [
  "all",
  "react",
  "nodejs",
  "nextjs",
  "spring",
  "spring boot",
];

export default portfolios;

imgsrc는 이미지 경로 역할을 할것이고, filter는 해당 이미지를 필터링 할 목록이다.

3. portfolio 페이지

pages/portfolio

import Image from "next/image";
import Container from "../../components/Container";
import portfolios, { filters } from "../../data/portfolios";

const Portfolio = () => {
  return (
    <Container>
      <div className="mt-10 flex flex-col shadow-[0_1px_1px_0px_rgba(0,0,0,0.08)]">
        <ul className="flex justify-around">
          {filters.map((filter) => (
            <li
              className={"h-14 flex items-center px-4 uppercase font-bold "}
              key={filter}
            >
              {filter}
            </li>
          ))}
        </ul>
      </div>
      <section className="cd-gallery mt-10 pt-10">
        <div className="flex flex-wrap justify-start box-content max-w-screen-lg">
          {portfolios.map((port, idx) => (
            <div
              key={`port ${idx}`}
              className={
                "w-full sm:w-1/2 lg:w-1/3 my-4 flex items-center justify-center "}
            >
              <div className="shadow-[0_1px_2px_0px_rgba(0,0,0,0.1)]">
                <Image
                  src={port.imgsrc}
                  alt={`Image ${idx + 1}`}
                  width={300}
                  height={390}
                />
              </div>
            </div>
          ))}
        </div>
      </section>
    </Container>
  );
};

export default Portfolio;

그동안은 bootstrab을 쓴다고는 했지만, css파일에 의존했는데, 이번에는 온전히 tailwind만으로 css작업을 해봤다...

확실히 이렇게하니 tailwind나 bootstrab의 장단점이 보인다.

  • 장점 CSS를 작성할 때 시간을 많이 절약할 수 있음 컴포넌트 생성과 관리가 쉬우며, 유지보수하기 편함

  • 단점 CSS가 필요할 때가 오는데, 이때 일관성을 해칠 수 있음 className이 끝도없이 길어짐

이제 이렇게하고 useState를 이용한 필터링 작업을 한번 해보자!

3 필터링

3.1 필터

pages/portfolio

import Image from "next/image";
import Container from "../../components/Container";
import portfolios, { filters } from "../../data/portfolios";
import { useState } from "react";

const Portfolio = () => {
  const [selectedFilter, setSelectedFilter] = useState("all");
  const handleFilterClick = (selectedType: string) => {
    setSelectedFilter(selectedType);
  };

  return (
    <Container>
      <div className="mt-10 flex flex-col shadow-[0_1px_1px_0px_rgba(0,0,0,0.08)]">
        <ul className="flex justify-around">
          {filters.map((filter) => (
            <li
              className={
                "h-14 flex items-center px-4 uppercase font-bold " +
                (selectedFilter === filter
                  ? "text-purple-900 shadow-[0_2px_0px_0px_rgba(65,48,124,1)]"
                  : "")
              }
              key={filter}
              onClick={() => handleFilterClick(filter)}
            >
              {filter}
            </li>
          ))}
        </ul>
      </div>
      <section className="cd-gallery mt-10 pt-10">
        ...
      </section>
    </Container>
  );
};

export default Portfolio;

이러면, 되고!

pages/portfolio

<section className="cd-gallery mt-10 pt-10">
  <div className="flex flex-wrap justify-start box-content max-w-screen-lg">
    {portfolios.map((port, idx) => (
      <div
        key={`port ${idx}`}
        className={
          "w-full sm:w-1/2 lg:w-1/3 my-4 flex items-center justify-center " +
          (port.filter.includes(selectedFilter) ? "" : "hidden")
        }
      >
        <div className="shadow-[0_1px_2px_0px_rgba(0,0,0,0.1)]">
          <Image
            src={port.imgsrc}
            alt={`Image ${idx + 1}`}
            width={300}
            height={390}
          />
        </div>
      </div>
    ))}
  </div>
</section>

section 안쪽부분은 이렇게 처리하면 된다!

이제 여기까지 하고, 직접 필터를 눌러보면 잘 적용이 된다!