본문 바로가기
Tutorial/port2023

40. 포트폴리오 사이트 만들기 : Next-Site : 마무리

by @webstoryboy 2023. 8. 1.
Tutorial/portfolio

포트폴리오 사이트 만들기 - Next

by @webs 2023. 08. 01.
10
포트폴리오 사이트 만들기 : 마무리
난이도 중간

소개

안녕하세요! 웹스토리보이입니다. 이제 정말 마지막단계입니다. 지금까지 잘 따라오셨습니다. 마지막까지 최선을 다해 성공합시다. 화이팅 👍

포트폴리오 사이트 만들기

VITE SITE

  • 1. 셋팅하기
    • 1_1. vite 설치하기
    • 1_2. vite 폴더 정리하기
    • 1_3. gsap/lenis 설치하기
    • 1_4. git 연동하기
  • 2. 레이아웃
    • 2.1 레이아웃 구조 만들기
    • 2.2 메인 레이아웃 구조 만들기
    • 2.3 CSS 셋팅하기
    • 2.4 JavaScript 셋팅하기
  • 3. 헤더 영역
    • 3.1 헤더 구조 잡기
    • 3.2 헤더 디자인 설정
    • 3.3 반응형 작업하기
    • 3.4 메뉴 자바스크립트 설정
  • 4. 인트로 영역
    • 4.1 인트로 구조 잡기
    • 4.2 인트로 디자인 설정
    • 4.3 반응형 작업하기
  • 5. 스킬 영역
    • 5.1 스킬 구조 잡기
    • 5.2 스킬 디자인 설정
    • 5.3 반응형 작업하기
  • 6. 사이트 영역
    • 6.1 사이트 구조 잡기
    • 6.2 사이트 디자인 설정
    • 6.3 반응형 작업하기
  • 7. 포트폴리오 영역
    • 7.1 사이트 구조 잡기
    • 7.2 사이트 디자인 설정
    • 7.3 반응형 작업하기
    • 7.4 스크립트 작업하기
  • 8. 연락처 영역
    • 8.1 연락처 구조 잡기
    • 8.2 연락처 디자인 설정
    • 8.3 반응형 작업하기
  • 9. 푸터 영역
    • 9.1 푸터 구조 잡기
    • 9.2 푸터 디자인 설정
    • 9.3 반응형 작업하기
  • 10. 마무리
    • 10.1 스무스 효과주기
    • 10.2 링크 연결하기
    • 10.3 netlify에 배포하기

REACT SITE

  • 1. 셋팅하기
    • 1_1. React 설치하기
    • 1_2. React 폴더 정리하기
    • 1_3. 라이브러리 설치하기
    • 1_4. git 연동하기
  • 2. 라우팅 및 컴퍼넌트
    • 2_1. 라우팅 설정하기
    • 2_2. 컴퍼넌트 설정하기
    • 2_3. SCSS 설정하기
  • 3. 헤더 영역
    • 3_1. 헤더 구조잡기
    • 3_2. 헤더 디자인 설정
    • 3_3. 헤더 데이터 작업
    • 3_4. 헤더 토글 메뉴 작업하기
  • 4. 인트로 영역
    • 4_1. 인트로 구조잡기
    • 4_2. 인트로 디자인 설정
    • 4_3. 인트로 데이터 작업
  • 5. 스킬 영역
    • 5_1. 스킬 구조잡기
    • 5_2. 스킬 디자인 설정
    • 5_3. 스킬 데이터 작업
  • 6. 사이트 영역
    • 6_1. 사이트 구조잡기
    • 6_2. 사이트 디자인 설정
    • 6_3. 사이트 데이터 작업
  • 7. 포트폴리오 영역
    • 7_1. 포트폴리오 구조잡기
    • 7_2. 포트폴리오 디자인 설정
    • 7_3. 포트폴리오 데이터 작업
  • 8. 연락처 영역
    • 8_1. 연락처 구조잡기
    • 8_2. 연락처 디자인 설정
    • 8_3. 연락처 데이터 작업
  • 9. 푸터 영역
    • 9_1. 푸터 구조잡기
    • 9_2. 푸터 디자인 설정
    • 9_3. 푸터 데이터 작업
  • 10. 마무리
    • 10_1. 데이터 통합하기
    • 10_2. 스무스 효과 넣어주기
    • 10_3. 가로모드 구현하기
    • 10_4. netlify에 배포하기

VUE SITE

  • 1. 셋팅하기
    • 1_1. Vue 설치하기
    • 1_2. Vue 폴더 정리하기
    • 1_3. 라이브러리 설치하기
    • 1_4. git 연동하기
  • 2. 라우팅 및 컴퍼넌트
    • 2_1. 라우팅 설정하기
    • 2_2. 컴퍼넌트 설정하기
    • 2_3. SCSS 설정하기
  • 3. 헤더 영역
    • 3_1. 헤더 구조잡기
    • 3_2. 헤더 디자인 설정
    • 3_3. 헤더 데이터 작업
    • 3_4. 헤더 토글 메뉴 작업하기
  • 4. 인트로 영역
    • 4_1. 인트로 구조잡기
    • 4_2. 인트로 디자인 설정
    • 4_3. 인트로 데이터 작업
  • 5. 스킬 영역
    • 5_1. 스킬 구조잡기
    • 5_2. 스킬 디자인 설정
    • 5_3. 스킬 데이터 작업
  • 6. 사이트 영역
    • 6_1. 사이트 구조잡기
    • 6_2. 사이트 디자인 설정
    • 6_3. 사이트 데이터 작업
  • 7. 포트폴리오 영역
    • 7_1. 포트폴리오 구조잡기
    • 7_2. 포트폴리오 디자인 설정
    • 7_3. 포트폴리오 데이터 작업
  • 8. 연락처 영역
    • 8_1. 연락처 구조잡기
    • 8_2. 연락처 디자인 설정
    • 8_3. 연락처 데이터 작업
  • 9. 푸터 영역
    • 9_1. 푸터 구조잡기
    • 9_2. 푸터 디자인 설정
    • 9_3. 푸터 데이터 작업
  • 10. 마무리
    • 10_1. 스무스 효과 넣어주기
    • 10_2. 가로모드 구현하기
    • 10_3. 링크 클릭 구현하기
    • 10_4. netlify에 배포하기

NEXT SITE

  • 1. 셋팅하기
    • 1_1. Next 설치하기
    • 1_2. Next 폴더 정리하기
    • 1_3. 라이브러리 설치하기
    • 1_4. git 연동하기
  • 2. 라우팅 및 컴퍼넌트
    • 2_1. 라우팅 설정하기
    • 2_2. 컴퍼넌트 설정하기
    • 2_3. SCSS 설정하기
    • 2_4. Script 설정하기
  • 3. 헤더 영역
    • 3_1. 헤더 구조잡기
    • 3_2. 헤더 디자인 설정
    • 3_3. 헤더 데이터 작업
    • 3_4. 헤더 토글 메뉴 작업하기
  • 4. 인트로 영역
    • 4_1. 인트로 구조잡기
    • 4_2. 인트로 디자인 설정
    • 4_3. 인트로 데이터 작업
  • 5. 스킬 영역
    • 5_1. 스킬 구조잡기
    • 5_2. 스킬 디자인 설정
    • 5_3. 스킬 데이터 작업
  • 6. 사이트 영역
    • 6_1. 사이트 구조잡기
    • 6_2. 사이트 디자인 설정
    • 6_3. 사이트 데이터 작업
  • 7. 포트폴리오 영역
    • 7_1. 포트폴리오 구조잡기
    • 7_2. 포트폴리오 디자인 설정
    • 7_3. 포트폴리오 데이터 작업
  • 8. 연락처 영역
    • 8_1. 연락처 구조잡기
    • 8_2. 연락처 디자인 설정
    • 8_3. 연락처 데이터 작업
  • 9. 푸터 영역
    • 9_1. 푸터 구조잡기
    • 9_2. 푸터 디자인 설정
    • 9_3. 푸터 데이터 작업
  • 10. 마무리
    • 10_1. 스무스 효과 넣어주기
    • 10_2. 링크 클릭 구현하기
    • 10_3. 가로모드 구현하기
    • 10_4. netlify에 배포하기

10. 마무리

10.1 스무스 효과 넣어주기

스크립트 셋팅은 처음에 다 해줬기 때문에 lenis.js에 파일만 넣어주면 됩니다.

import Lenis from "@studio-freight/lenis";

const lenis = () => {
    const lenis = new Lenis({
        duration: 1,
        easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
    });

    function raf(time) {
        lenis.raf(time);
        requestAnimationFrame(raf);
    }

    requestAnimationFrame(raf);

    lenis.on("scroll", (e) => {
        console.log(e);
    });
};

export default lenis;

10.2 링크 클릭 구현하기

이 부분도 link.js에 다음과 같이 작업합니다.

const link = () => {
    document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
        anchor.addEventListener("click", function (e) {
            e.preventDefault();

            const targetId = this.getAttribute("href");
            const targetElement = document.querySelector(targetId);

            if (targetElement) {
                targetElement.scrollIntoView({ behavior: "smooth" });
            }
        });
    });
};

export default link;
  • const link = () => { ... }: link라는 이름의 화살표 함수(arrow function)를 정의합니다. 이 함수는 스크롤 내비게이션 기능을 구현하는 로직을 담고 있습니다.
  • document.querySelectorAll('a[href^="#"]').forEach((anchor) => { ... }): 문서(Document) 내에서 href 속성이 #으로 시작하는 모든 <a>(앵커) 요소들을 선택합니다. 이후 forEach 메서드를 사용하여 선택된 모든 앵커 요소들에 대해 콜백 함수를 실행합니다.
  • anchor.addEventListener("click", function (e) { ... }): 각 앵커 요소에 클릭 이벤트 리스너를 추가합니다. 이렇게 하면 앵커를 클릭할 때마다 콜백 함수가 실행됩니다.
  • e.preventDefault();: 이벤트의 기본 동작을 취소합니다. 앵커를 클릭하면 기본적으로 해당 앵커의 링크로 이동하는 동작을 취소하여 페이지가 새로고침되지 않도록 합니다.
  • const targetId = this.getAttribute("href");: 클릭된 앵커의 href 속성 값을 가져옵니다. 이 값은 클릭한 앵커의 목적지 요소를 찾는데 사용됩니다.
  • const targetElement = document.querySelector(targetId);: targetId로 지정된 요소를 문서에서 찾습니다. targetId는 #을 포함한 앵커의 링크값이므로, 해당 앵커의 링크로 이동할 위치의 요소를 검색합니다.
  • if (targetElement) { ... }: targetElement가 존재하면, 즉 링크로 이동할 위치의 요소가 존재하면 다음 블록을 실행합니다.
  • targetElement.scrollIntoView({ behavior: "smooth" });: targetElement로 지정된 요소로 스크롤을 부드럽게 이동합니다. 이 때 behavior: "smooth" 옵션을 사용하여 스크롤이 부드럽게 이동하도록 합니다.

10.3 가로모드 구현하기

포트폴리오를 보여주는 가로모드를 구현하겠습니다. 이 부분은 port.jsx에서 작업을 하겠습니다.

import React, { useEffect, useRef } from "react";
import Image from "next/image";

import { portText } from "../constants";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";

const Port = () => {
    const horizontalRef = useRef(null);
    const sectionsRef = useRef([]);

    useEffect(() => {
        gsap.registerPlugin(ScrollTrigger);
    
        const horizontal = horizontalRef.current;
        const sections = sectionsRef.current;
    
        let scrollTween = gsap.to(sections, {
            xPercent: -120 * (sections.length - 1),
            ease: "none",
            scrollTrigger: {
                trigger: horizontal,
                start: "top 56px",
                end: () => "+=" + horizontal.offsetWidth,
                pin: true,
                scrub: 1,
                invalidateOnRefresh: true,
                anticipatePin: 1,
            },
        });
    
        return () => {
            scrollTween.kill();
        };
    }, []);

    return (
        <section id="port" ref={horizontalRef}>
            <div className="port__inner">
                <h2 className="port__title">
                    portfolio <em>포폴 작업물</em>
                </h2>
                <div className="port__wrap">
                    {portText.map((port, key) => (
                        <article  
                            className={`port__item p${key + 1}`} 
                            key={key} 
                            ref={(el) => (sectionsRef.current[key] = el)}
                        >
                            <span className="num">{port.num}.</span>
                            <a href={port.code} target="_blank" className="img" rel="noreferrer">
                                <Image src={port.img} alt={port.title} width={420} height={262} />
                            </a>
                            <h3 className="title">{port.title}</h3>
                            <p className="desc">{port.desc}</p>
                            <a href={port.view} target="_blank" className="site" rel="noreferrer">사이트 보기</a>
                        </article>
                    ))}
                </div>
            </div>
        </section>
    )
}

export default Port 
  • useEffect는 컴포넌트가 렌더링된 후에 특정 동작을 실행하는 훅입니다. 여기서는 GSAP의 ScrollTrigger 플러그인을 등록하고, 가로 스크롤 애니메이션을 적용하는 로직을 설정합니다. 의존성 배열 []을 전달하여 마운트된 후 한 번만 실행되도록 합니다.
  • useRef는 React에서 DOM 노드 또는 다른 값의 변경 여부를 감지할 때 사용하는 훅입니다. 여기서 horizontalRef는 가로 스크롤 컨테이너를 가리키는 DOM 노드를 참조하고, sectionsRef는 각 포트폴리오 항목 요소들을 참조하는 배열을 생성합니다.

10.4 netlify에 배포하기

깃헙에 모든 소스를 올리겠습니다.

git add .
git commit -m "🥺 마무리 완료"
git push -u origin main

이제 빌드를 한번해보겠습니다. 지금까지 작업했던 소스는 브라우저가 읽을 수 없습니다. 브라우저가 읽을 수 있도록 컴파일을 해주고 빌드 작업을 해주어야 브라우저에서 볼 수 있습니다. 빌드 과정을 통해 소스는 가벼워지고 효율성이 증가됩니다.

$ npm run build

빌드화 과정을 거치면 .next 폴더에 파일이 생깁니다.

webstoryboy@Webstoryboyui-MacBookPro next-site % npm run build

> next-site@0.1.0 build
> next build

Warning: For production Image Optimization with Next.js, the optional 'sharp' package is strongly recommended. Run 'yarn add sharp', and Next.js will use it automatically for Image Optimization.
Read more: https://nextjs.org/docs/messages/sharp-missing-in-production
- info Creating an optimized production build  
- info Compiled successfully
- info Linting and checking validity of types  
- info Collecting page data  
- info Generating static pages (3/3)
- info Finalizing page optimization  

Route (app)                                Size     First Load JS
─ ○ /                                      58.6 kB         137 kB
+ First Load JS shared by all              78.1 kB
    ├ chunks/596-502b6f304d168aed.js         25.7 kB
    ├ chunks/fd9d1056-c9f151c58d427982.js    50.5 kB
    ├ chunks/main-app-e5c7c3938b6b9060.js    216 B
    └ chunks/webpack-0bb8a6bc12122529.js     1.68 kB

Route (pages)                              Size     First Load JS
─ ○ /404                                   182 B          75.6 kB
+ First Load JS shared by all              75.4 kB
    ├ chunks/framework-8883d1e9be70c3da.js   45 kB
    ├ chunks/main-d62d37922d9e063a.js        28.5 kB
    ├ chunks/pages/_app-52924524f99094ab.js  195 B
    └ chunks/webpack-0bb8a6bc12122529.js     1.68 kB

○  (Static)  automatically rendered as static HTML (uses no initial props)

마지막으로 다시 한번 업로드 해보겠습니다. 이렇게 올려도 깃헙에는 큰 변화가 없을 것입니다. .gitignore파일에 build 폴더가 포함되어 있기 때문에 파일은 올라가지 않습니다.

git add . 
git commit -m "😇 1차 완성본"
git push -u origin main

이제 netlify 사이트로 이동하겠습니다. 로그인을 하고 add new site 버튼을 누르고 import an existing project를 선택하겠습니다.

netlify

deploy width GitHub 버튼을 클릭하고 port2023-next를 검색 후 선택합니다.

netlify

자동으로 next 파일을 인식합니다. 따로 수정할 필요는 없습니다. 바로 Deploy port2023-next 버튼을 클릭하면 됩니다. 자동으로 빌드가 되고 배포가 됩니다.

netlify

완료가 되었습니다. Domain setting을 누르면 도메인을 변경할 수 있습니다.

netlify

마지막으로 깃헙에 정리하면 되겠습니다. 메모장에도 같이 정리하겠습니다.

netlify

3. 마무리

드뎌 모든게 마무리 되었습니다. 하나의 사이트를 네가지 버젼으로 만들었습니다. 기초적인 흐름을 이해하기 위한 튜토리얼입니다. 이제 조금 감이 잡히면 이제는 한단계 더 깊이 들어가봅시다. 다음 강의에는 조금 더 파고드는 강의를 만들겠습니다. 그 동안 정말 수고하셨습니다. 👍👍✊


예제 목록

댓글