코딩/React 본 캠프

[본 캠프 5일차] 07.19 팀 프로젝트 종료

James Song 2024. 7. 19. 09:21
반응형

html, css, js 최종 합치지말고 각 기능별로 나눠서 한 파일안에 넣기

 

  • 원페이지 스크롤
    - Scroll-snap-type : js없이 css로도 구현 가능함
    - scrollTo() 메소드로 사용 (js)
  • 모달
    - Modal 이라는 태그 사용하면 간단함 (html 에 나옴)
  • 이미지 css
    - Object-fit: cover (이미지 비율 안 깨짐)
  • localStorage
    - 다크모드도 저장할 수 있음 (다크모드인지 아닌지 유지)Flash 현상을 막기 위해서는 브라우저 렌더링 중요함
    - Prefer-color-sheme : 들어오는 유저한테도 자동으로 다크모드를 적용시킬 수 있음
    - 브라우저 렌더링 프로세스 찾아보기

* display: none vs visibility hidden (면접 질문)
* 스크롤 이벤트에 “쓰로틀링” 으로 과부하 막기

* XMLHttpRequest 구버전 >> fetch 신버전
* 반응형 디자인을 사용할때는 미디어쿼리를 사용한다.

* scroll: smooth 스크롤을 부드럽게

 

헤더 부분
팀 소개

 

팀원 소개
댓글창 기능

 

 <section class="member_wrapper">
      <div class="wrap" id="team-member">
        <h2 class="team-title">코린이들을 소개합니다!</h2>
        <p>
          코린이들을 소개합니다! <br />
          마우스로 팀원의 이모지를 클릭해 보세요!
        </p>
        <div class="team-container"></div>
      </div>
    </section>

html 부분

 

.team-image {
  width: 100%;
  height: 350px;
  border-radius: 10px;
}

.team-member {
  background-color: rgb(111, 140, 160);
  width: 100%;
  height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.team-member > h3 {
  margin: 0;
  padding-top: 30px;
}

.member {
  width: 50%;
}

.comment {
  width: 100%;
  height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

/* team 전체 감싸는 wrap */
.wrap {
  height: 100vh;
  padding: 120px 80px;
}

/* TeamTitle css 추가 Start */
.team-title {
  position: relative;
  width: 500px;
  padding-bottom: 30px;
}

.team-title::before {
  width: 100%;
  background: #f2f2f2;
}

.team-title::after {
  width: 180px;
  background: #0d0058;
}

.team-title::before,
.team-title::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  height: 4px;
  border-radius: 2px;
}

#team-member p {
  padding-top: 40px;
  font-size: 20px;
  line-height: 30px;
}
/* TeamTitle css 추가 End */
.team-container {
  display: flex;
  align-items: center;
  text-align: center;
  justify-content: center;
  height: 50vh;
}

.member {
  display: inline-block;
  margin: 20px;
  width: 250px;
  position: relative;
}

.photo {
  width: inherit;
  height: inherit;
  position: relative;
  overflow: hidden;
  border-radius: 15px;
}

.photo img {
  width: 100%;
  height: 100%;
}

.photo .overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity 0.3s;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: 20px;
}

.photo:hover .overlay {
  opacity: 1;
  cursor: pointer;
}

.icons {
  margin-top: 10px;
}

.icons a img {
  height: 35px;
  margin: 5px;
  transition: transform 0.3s;
}

.icons a img:hover {
  transform: scale(1.2);
}

css

 

document.addEventListener("DOMContentLoaded", function () {
  const teamContainer = document.querySelector(".team-container");
  const imagePath = "./image/";

  // 프로필
  const members = [
    {
      name: "신OO",
      github: `${imagePath}github-remove.png`,
      velog: `${imagePath}velog-remove.png`,
      githubLink: "https://github.com/HBeom00",
      velogLink: "https://velog.io/@hbeom00/posts",
      backgroundImage: `${imagePath}shin_profile.png`,
      age: 23,
      advantages: "끈기 있다.",
      style: "꼼꼼하다.",
      tmi: "더위를 많이 타서 여름이 힘들다...",
      imgSrc: `${imagePath}shin.jpg`,
    },
    {
      name: "김OO",
      github: `${imagePath}github-remove.png`,
      velog: `${imagePath}velog-remove.png`,
      githubLink: "https://github.com/duddlfkd02",
      velogLink: "https://velog.io/@duddlfkd02/posts",
      backgroundImage: `${imagePath}kim_profile.png`,
      age: 26,
      advantages: "해야하는 일에 대해 계획성 있게 처리 가능해요",
      style: "겁이 많지만 악바리로 해내는 스타일",
      tmi: "빨래를 했는데 비가 옵니다...",
      imgSrc: `${imagePath}kim.jpeg`,
    },
    {
      name: "송OO",
      github: `${imagePath}github-remove.png`,
      velog: `${imagePath}tstory-remove.png`,
      githubLink: "https://github.com/spmrsong",
      velogLink: "https://pokbeg.tistory.com/",
      backgroundImage: `${imagePath}song_profile.png`,
      age: 28,
      advantages: "궁금증이 정말 많아서 이것저것 도전해본다.",
      style:
        "비전공자라 굉장히 꼼꼼하게 찾아보지만 결국엔 GPT 의 도움을 받는다.",
      tmi: "24시간 에어컨 틀고 있어서 전기세가 걱정됩니다. 그리고 지금 음악 듣고 싶네요.",
      imgSrc: `${imagePath}song2.png`,
    },
    {
      name: "서OO",
      github: `${imagePath}github-remove.png`,
      velog: `${imagePath}velog-remove.png`,
      githubLink: "https://github.com/youngjin34",
      velogLink: "https://velog.io/@epik34/posts",
      backgroundImage: `${imagePath}seo_profile.png`,
      age: 30,
      advantages: "가끔씩 나서길 좋아한다..! 그래서 분위기를 좋게 만든다.",
      style: "chat gpt와 대화를 잘 나눈다....?ㅎㅎ",
      tmi: "맛있는 거 먹으면서 살 찔 때가 제일 좋아...",
      imgSrc: `${imagePath}seo.jpg`,
    },
    {
      name: "이OO",
      github: `${imagePath}github-remove.png`,
      velog: `${imagePath}velog-remove.png`,
      githubLink: "https://github.com/wldud7788",
      backgroundImage: `${imagePath}lee_profile.png`,
      age: 30,
      advantages: "마음먹은건 어떻게 해서든 꼭 해내요!",
      style: "계획적이고 체계적인걸 좋아하는 스타일",
      tmi: "강아지가 편식을 해요... 배가 불렀나봐요..",
      imgSrc: `${imagePath}lee.jpg`,
    },
  ];

  members.forEach((member, idx) => {
    const memberDiv = document.createElement("div");
    memberDiv.className = "member";

    memberDiv.innerHTML = `
            <div class="photo member_content" id="member_content_${idx}">
                <img src="${member.backgroundImage}" alt="${member.name}">
                <div class="overlay">${member.name}</div>
            </div>
            <div class="icons">
                <a href="${member.githubLink}" target="_blank"><img src="${
      member.github
    }" alt="GitHub"></a>
                <a href="${member.velogLink}" target="_blank"><img src="${
      member.velog
    }" alt="${member.name === "송OO" ? "Tstory" : "Velog"}"></a>
            </div>
        `;

    teamContainer.appendChild(memberDiv);

    // Add event listener for each member to show modal
    const memberContent = document.getElementById(`member_content_${idx}`);
    memberContent.addEventListener("click", () => {
      showModal(members[idx]);
    });
  });

  const closeBtn = document.getElementById("close-modal");
  const teamModal = document.getElementById("modal_container");

  function showModal(member) {
    teamModal.style.display = "none";
    teamModal.style.display = "flex"; // flex로 변경하여 중앙에 위치하도록 함

    // 멤버 사진
    const imgBox = document.getElementById("member_image");
    imgBox.innerHTML = `<img src="${member.imgSrc}" alt="${member.name}">`;

    // 멤버 이름, 나이
    const memberName = document.getElementById("member_name");
    const memberAge = document.getElementById("member_age");
    memberName.innerText = member.name;
    memberAge.innerText = member.age + "살";

    // 멤버 내용
    const memberInfo = document.getElementById("member_content");
    memberInfo.innerHTML = `
            <div class="content_inner">
                <img src="${imagePath}icon-agree.png" alt="협업" class="modal_icon">
                ${member.style}
            </div>
            <div class="content_inner">
                <img src="${imagePath}icon-positive.png" alt="장점" class="modal_icon">
                ${member.advantages}
            </div>
            <div class="content_inner">
                <img src="${imagePath}icon-tmi.png" alt="tmi" class="modal_icon">
                ${member.tmi}
            </div>
        `;
    disableScroll();
  }

script

 

 

일주일동안 너무나도 좋은 팀원분들을 만나서 팀 프로젝트를 완료한 것 같아 행복했고,

도움이 되지 못한 것 같아 너무 죄송하고 아쉬웠습니다.

다음에는 공부를 더 열심히 해서 서로 머리 맞대고 같이 고민할 수 있을 정도로 실력을 키워서 도움이 되고 싶네요.

 

 

반응형