[Next.js] 포트폴리오 웹 페이지 제작기 - 4. About과 Contact 섹션

olwooz·2023년 2월 9일
0

어제에 이어 메인 콘텐츠 레이아웃 배치를 완료하려 한다.

About

나에 대한 소개글을 작성할 곳이다. 왼쪽에는 글, 오른쪽에는 사진을 배치할 것이다.
<p>태그 스타일을 통일시키고 paragraph 갯수에 상관 없이 변경하고 재사용하기 쉽도록
AboutText 컴포넌트도 같이 만들어줬다.
사진이 들어갈 div의 크기는 실제 사진 크기 비율에 맞춰서 상수로 설정했다.

// components/Contents/About/About.tsx
import ContentWrapper from '../ContentWrapper';
import AboutText from './AboutText';

const IMG_WIDTH = 'w-[432px]';
const IMG_HEIGHT = 'h-[540px]';
const p1 =
  'Lorem ipsum dolor sit amet consectetur adipisicing elit. Reiciendis nisi nemo eos? Quod reiciendis, commodi unde vel ducimus voluptatem? Dignissimos velit hic, in id placeat perferendis corporis distinctio sunt cum.';
const p2 =
  'Lorem ipsum dolor sit amet consectetur adipisicing elit. Consectetur dolore illum inventore repudiandae perferendis nesciunt, et, earum, quod alias corrupti reiciendis pariatur repellendus voluptates debitis modi dolor nobis ex soluta! Reiciendis eveniet ipsam veniam mollitia incidunt nisi consequuntur fugiat quis dicta quisquam. Nisi animi, ad quam alias voluptas perferendis blanditiis aut expedita repellendus voluptate doloremque in assumenda hic explicabo maiores corporis, fuga sapiente ratione magnam laboriosam non nulla error? Dolores, vero nesciunt esse soluta perspiciatis beatae rem neque officiis. Facilis veniam dolore blanditiis! Ducimus blanditiis officiis, nostrum soluta sequi maiores. Consequuntur perferendis hic alias ex nostrum dignissimos amet pariatur eligendi.';

const About = () => {
  return (
    <ContentWrapper style="flex justify-between">
      <div className="ml-[100px] mr-[100px]">
        <h1 className="mb-8 text-5xl font-thin">About</h1>
        <AboutText content={p1} />
        <AboutText content={p2} />
      </div>
      // ※
      <div className={`mr-[100px] ${IMG_HEIGHT} ${IMG_WIDTH} border-2 border-dashed border-gray-400`}>Photo</div>
    </ContentWrapper>
  );
};

export default About;

※ 여기서 tailwind의 arbitrary value를 h-[${IMG_HEIGHT}px]과 같이 정의하는 방식은 유효하지 않다. (https://tailwindcss.com/docs/content-configuration#dynamic-class-names)

// components/Contents/About/AboutText.tsx

interface Props {
  content: string;
}

const AboutText = ({ content }: Props) => {
  return <p className="mb-8">{content}</p>;
};

export default AboutText;

결과

Contact

Project 섹션은 작업이 커질 것 같아서 Contact 섹션 작업을 먼저 하려고 한다.
포트폴리오 페이지에서는 이메일까지만 공개할 것 같지만, 혹시 모르니 여러 연락 수단을 페이지에 배치할 수 있도록 구현했다.

About에서와 마찬가지로 각 연락 수단을 개별 컴포넌트 ContactInfo로 만들어서 변경과 재사용을 용이하게 만들었고, 하단 아이콘 바를 만들 때처럼 이미지마다 컴포넌트를 만드는 건 다소 불필요하다 느껴져서 public 폴더에 icons 폴더를 생성해 아이콘 파일들을 넣었다.

// components/Contents/Contact/Contact.tsx
import ContentWrapper from '../ContentWrapper';
import ContactInfo from './ContactInfo';

const Contact = () => {
  return (
    <ContentWrapper style="flex item-center">
      <div className="m-auto text-center">
        <h1 className="pb-48 text-5xl font-thin">Contact</h1>
        <div className="pb-12">
          <ContactInfo info="010-1234-1234" image="/icons/phone.png" />
          <ContactInfo info="email@email.com" image="/icons/email.png" link="mailto:email@email.com" />
          <ContactInfo info="kakaotalk" image="/icons/talk.svg" />
        </div>
        <p className="text-sm font-light">연락 주세용 *^^*</p>
      </div>
    </ContentWrapper>
  );
};

export default Contact;
// components/Contents/Contact/ContactInfo.tsx

import Image from 'next/image';
import Link from 'next/link';

interface Props {
  info: string;
  image: string;
  link?: string;
}

const ContactInfo = ({ info, image, link }: Props) => {
  const InfoElem = (
    <>
      <Image src={image} alt={info} width="20" height="20" className="mr-4 inline-block" />
      <p className="inline-block align-middle text-lg font-bold">{info}</p>
    </>
  );

  return <div className="inline-block w-[18vw] p-12 text-center">{link ? <Link href={link}>{InfoElem}</Link> : InfoElem}</div>;
};

export default ContactInfo;

결과

Project 섹션을 어떻게 그려낼 지 생각하다가 Framer Motion을 써 보느라 시간이 좀 지체됐다. 내일은 Project 섹션에 carousel을 구현해보겠다.

0개의 댓글