3. What / Q&A / Contact 파트 구현

박준혁·2023년 6월 1일
0

홈페이지 메인 페이지에서 남은 화면들을 구현하는 과정을 정리해보고자 한다. 앞서 NavBar, Home, About을 구현하였고, 남은 What, Q&A, Contact 방식을 구현해보고자 한다.

What 파트 구현

먼저 활동에 대해서 구체적으로 설명하는 What We Do 파트이다. 해당 파트에서는 크게 4가지로 설명할 수 있는 동아리 활동에 대하여 각각 소개를 하고, 동아리에서 가장 중점적인 활동이라고 볼 수 있는 '팀 프로젝트'와 관련하여 팀별로 어떠한 주제의 프로젝트를 진행했는지 설명한다. 동아리 활동에 대한 것은 크게 다룰 것이 없고, 마우스 hover할 때 애니메이션 효과만 주면 되지만, 팀 프로젝트의 경우 팀 이름을 클릭할 때 아래에 해당 팀에서 진행한 프로젝트에 대한 설명이 나타나도록 할 것이기 때문에 "Button, State"와 같은 것을 사용해야 할 것으로 판단하였다. 따라서 What 파트는 client Rendering 방식을 사용하기 위해 새로운 파일에 제작하였다.

Using Client

component라는 폴더 내부에 What.js라는 파일을 제작하고, 가장 상단에 'use client'를 작성하여 server side에서 rendering 되는 것이 아닌, client 차원에서 rendering 되는 방식을 사용하였다.

Activity Description

앞서 지정했던 class를 이용해 section title과 section line을 그리고, 총 4가지로 분류한 동아리 활동을 소개하여야 한다. 따라서 4가지 활동의 정보를 담은 object들을 list로 모아 정의하였다. 각각의 object는 name, summary, image, content로 구성되어 있다.

ActivityDiv

list 내부에 저장된 각각의 object들을 이용해 같은 코드의 반복을 줄이기 위해 활동에 대한 설명을 작성하는 새로운 함수를 아래와 같의 정의하여 사용하였다.

const ActivityDiv = ({name, summary, image, content, className=""}) => {
    return (
        <div className={`${className}}>
            <Image src={`/${image}`}"/>
            <h2>{name}</h2>
            <h4>{summary}</h4>
            <p>{content}</p>
        </div>
    )
}

전체적인 구조 파악을 위해 세부적인 tailwind css들은 생략을 하였지만, 각각의 activity 항목에 마우스를 hover 시켰을 때 시각적인 효과가 발생하면 좋을 것이라고 생각해 hover 시에 좌측과 상단으로 각각 8px 만큼 이동하고, shadow와 배경의 색이 변화하는 효과도 작성하였다. 해당 효과들은 이전과 같이 아래 코드를 통해 애니메이션 효과를 주었다.

transition-all ease-in-out duration-200

설명을 작성하는 ActivityDiv를 위와 같이 정의하였기 때문에 해당 함수를 이용하여 list에 저장한 object들을 가지고 변수들만 바꾸어 사용하면 된다. 그렇게 제작한 코드가 아래와 같다.

 <section className="flex-wrap">
            <div className=" flex flex-wrap items-center justify-center">
                <ActivityDiv {...activity[0]}/>
                <ActivityDiv {...activity[1]}/>
            </div>
            <div className="flex flex-wrap items-center justify-center">
                <ActivityDiv {...activity[2]}/>
                <ActivityDiv {...activity[3]}/>
            </div>
 </section>

flex-wrap 줄바꿈

4개의 ActivityDiv 항목을 모두 section 태그 내부 map 함수를 이용해 작성할 수 있었지만, 그렇게 될 경우 화면의 너비가 줄어들 때 오직 한개의 항목만이 다음 줄로 줄 바꿈이 되면서 항목이 줄 별로 3개, 1개가 되는 상황이 발생한다. 이런 현상을 방지하기 위해 각각 2개씩 div 태그로 감싸고, flex-wrap:wrap을 활성화시켰다. 그 결과 아래 사진과 같이 가로 너미가 점차 줄어들면 항목의 개수가 4개 -> 2개/2개 -> 줄 별 1개 로 변화함을 확인할 수 있다.

Activity 파트 결과

Team Project Description

동아리 활동에 대한 설명 이후에는 Team Project와 관련된 설명이다. 이전에 동아리에서는 어떠한 주제의 project가 진행 되었는지를 설명하는 페이지이다. 전반적인 구현 방식은 다음과 같다. useState를 이용해 현재 버튼이 눌린 팀의 index를 저장한다. (기본 값은 0) 버튼이 눌리면, 해당 팀과 대응되는 index로 state의 값을 변경한다. 그리고 버튼 아래 설명은 해당 index에 대응되는 설명을 출력하는 방식이다. 추가적으로 teamList라는 array에는 각 팀의 이름과 정보가 object 형식으로 저장되어있다.

useState, onClick Function

아래 코드가 useState와 버튼을 눌렀을 때(onClick 시) 실행될 selector 함수를 정의한 것이다. selector 함수의 경우 해당 눌린 버튼에 작성된 팀명을 teamList array에 저장된 팀명과 비교해, 동일한 object의 index로 state를 설정하는 함수이다.

const [activeTeam, setActiveTeam] = useState(0);
const selector = (event) => {
        setActiveTeam(teamList.findIndex((item)=>{return item.name === event.target.innerText}));
};

Team Project Button & Summary

아래는 버튼과 간단한 설명을 출력하는 코드이다. button의 경우 teamList에서 map 함수를 이용하여, 각각의 팀별 버튼을 제작하도록 하였다. 현재 버튼이 눌린 팀이라면 너비를 더 길게하고, 배경색과 글씨 색을 다른 버튼들과 다르게 하도록 크드를 작성하였다. onClick Function으로는 selector를 지정하였고, button의 경우에는 내부 항목으로 name을, 아래 설명에는 summary 내용을 작성하도록 하였다.

<div>
    {teamList.map((item)=>{
     return 
     (<button className={`${item===teamList[activeTeam] ?
     "active w-[150px] bg-blue-950/[0.8] text-white"
     :"bg-stone-400 hover:bg-slate-600"}`}
      onClick={selector}>
      	{item.name}
      </button>)})}
</div>
<div>
	{teamList[activeTeam].summary}
</div>

(이후 팀별 프로젝트 사진도 가능하다면 추가할 계획이다.)

What 파트에서 마지막 하단 우측 부분에 Notion 페이지로 이동할 수 있도록 하는 링크를 삽입하고자 한다. 해당 Notion에는 동아리의 과거 기수(1기부터)들이 진행한 프로젝트에 대한 더 자세한 정보를 얻을 수 있다. 해당 링크를 View More이라는 글에 추가하였다.

What 파트 최종 결과

Q&A 파트 구현

다음은 Q&A 파트이다. 동아리 리크루팅을 진행할 때 비교적 자주 물어보는 질문들과 답변을 포함한 동아리에 대한 전체적인 설명을 진행하는 곳이다. 질문 약 5개를 한 줄씩 작성하고, 해당 질문을 클릭하면, 답변이 아래로 펼쳐지는 Accordion 형태로 구현하였다. 이를 위해서 앞선 과정과 동일하게 onClick과 useState가 필요해 'use client'를 적용한 새로운 파일을 만들어 Q&A 파트를 구현하였다.

Accordion 구현

Accordion은 아래와 같은 방식으로 구현하였다. 먼저 temp라는 변수를 기본 false로 정의하고, 이후 아래 버튼을 눌렀을 때 해당 상태를 반전시키는 역할을 한다. 만약 temp가 true일 때는 아래 p 태그 내부에 있는 content (질문에 대한 답변)이 h-auto를 통해 자동으로 나타나고, false인 상태에서는 h-0(높이 0)을 통해 나타나지 못하게 하였다.

const Accordion = ({title,content}) => {
    const [temp,setTemp] = useState(false);
    return (
      <div>
        <button	onClick={()=>{setTemp(!temp)}}>
          {title}
        </button>
        <p className={`${temp ?
        'p-10 bg-slate-300/[0.5] text-black h-auto'
        :' text-white bg-white h-0 truncate'}`}>
		{content}
		</p>
      </div>
    )
  }

Accordion 이용 Q&A 구현

이전 What 파트와 동일하게 이번에도 질문과 답변을 object로 구성하여 5개를 모두 question이라는 이름의 list에 저장하였다. 따라서 list 원소 각각을 map 함수를 이용해 Accordion에 적용시키면 된다. 해당 코드는 아래와 같다.

<section id='question'>
        <h1 className='section_title'>Q&A</h1>
        <span className="section_line">&nbsp;</span>
        {question.map((item) => {
          return (<Accordian title = {item.q} content={item.a} />)
        })}
</section>

Q&A 파트 최종 결과

Contact 파트 구현

Contact 파트는 가장 간단하다. 동아리 연락 방식과 동아리방의 위치만 작성해주면 될 것으로 보인다. 따라서 동아리방 주소, 동아리 인스타그램 아이디와 링크, 개발자를 작성하여 마무리하였다.

0개의 댓글