← 개발 로그 목록

website: 랜딩 전체 섹션 조립 (Thumbnail~Footer)

/ 9분 분량 / 개발 로그

멋사 경희대 사이트 프로젝트의 메인 랜딩 페이지를 Figma 시안 기준으로 처음부터 끝까지 조립한 PR입니다. Thumbnail부터 Footer까지 총 9개 섹션을 하나의 페이지로 완성했습니다.

요약

이 PR은 feat/landing-full-sections 브랜치에서 작업되어 2026년 7월 9일 dev 브랜치에 병합됐습니다. Thumbnail(구 Hero), Introduce, IntroduceSession, Project, Members, Plan(연간 활동 계획), Blog, Recruit, Footer까지 랜딩 페이지의 전 섹션을 컴포넌트 단위로 나눠 구현하고 app/page.tsx에서 하나로 조립했습니다. 1588줄이 추가되고 76줄이 삭제된, 이번 프로젝트 프론트엔드에서 상당히 굵직한 작업이었습니다.

기존에 있던 feat/fe-main-landing 브랜치의 랜딩 구현을 대체하는 성격의 PR이기도 합니다. PR 설명에 따르면 박일하 작성자의 코드를 중심으로 교체하기로 팀 내에서 합의된 프론트라인이라고 합니다.

배경 및 목적

랜딩 페이지는 여러 사람이 각자 섹션을 만들다 보면 톤앤매너가 흩어지기 쉬운 영역입니다. 이 PR은 Figma 시안을 기준으로 전체 섹션을 한 번에 조립함으로써 기존에 병렬로 진행되던 랜딩 작업(feat/fe-main-landing)을 하나의 흐름으로 정리하는 목적을 가지고 있습니다.

PR 설명에는 #77 멤버 탭이 별도 라우트로 확장될 예정이라는 언급이 있고, 그에 맞춰 members/activities/recruit 라우트 스텁을 유지해뒀습니다. 또한 운영진 실명 등 실제 콘텐츠는 아직 PM·디자인 컨펌 전이라 placeholder로 남겨두고, 제목·이름·날짜·썸네일 같은 목업 데이터와 API 연동은 후속 작업으로 명시했습니다.

구현 내용

섹션 구조

components/sections/ 디렉토리 아래에 섹션별로 컴포넌트를 분리하고 app/page.tsx에서 순서대로 배치하는 구조를 택했습니다. 각 섹션은 독립된 파일로 관리되어 한 섹션의 수정이 다른 섹션에 영향을 주지 않습니다.

변경된 파일

  • frontend/src/app/globals.css — 다크 테마 컬러 변수, 섹션별 배경 글로우 애니메이션 (301줄 추가)
  • frontend/src/app/layout.tsx, frontend/src/app/page.tsx — 전체 페이지 조립
  • frontend/src/components/sections/Thumbnail.tsx (구 Hero) — 컴포넌트명 정리
  • frontend/src/components/sections/Introduce.tsx — 통계 카드, 헤드라인 크로스페이드
  • frontend/src/components/sections/IntroduceSession.tsx — 트랙별 세션 소개 카드
  • frontend/src/components/sections/Members.tsx — 운영진 소개 그리드
  • frontend/src/components/sections/Plan.tsx — 연간 활동 계획 타임라인
  • frontend/src/components/sections/Blog.tsx, Project.tsx, Recruit.tsx, Footer.tsx
  • frontend/src/fonts/gremlin.ts, Gremlin-Regular.otf — 커스텀 폰트 추가
  • 다양한 SVG 에셋 (session/, project/ 하위)

배경 글로우: SVG를 CSS로

globals.css에서 가장 눈에 띄는 부분은 Figma의 방사형 그라디언트 글로우를 data URI SVG로 인라인 처리한 방식입니다. Thumbnail 섹션은 3개 상태(State1~3)가 순차적으로 크로스페이드하는 애니메이션으로 구현되어 있습니다.

@keyframes hero-glow-1 {
  0% { opacity: 1; }
  25% { opacity: 1; }
  35% { opacity: 0; }
  92% { opacity: 0; }
  100% { opacity: 1; }
}

각 레이어가 서로 다른 타이밍에 나타나고 사라지도록 keyframe을 겹쳐 짜서 21초 주기로 이전 상태를 완전히 덮어씌우는 크로스페이드를 만들었습니다. prefers-reduced-motion: reduce 미디어 쿼리로 모션 축소 설정을 존중하는 처리도 함께 들어갔습니다.

Members 섹션: 좌표를 퍼센트로 환산

Members 컴포넌트는 Figma 시안의 절대 좌표(px)를 그대로 쓰지 않고 퍼센트로 환산해서 반응형에 대응하도록 짰습니다.

const CARD =
  'relative rounded-[20px] border border-[rgba(255,80,0,0.22)] bg-[rgba(18,18,18,0.55)] backdrop-blur-[6px]';

function LeadCard({ role, name, dept, desc }: Lead) {
  return (
    <div className={CARD}>
      <div className={PHOTO} style={{ left: '3.103%', top: '8.14%', width: '41.379%', height: '85.068%' }} />
      ...

리드(회장/부회장), 세션장, 홍보부장 세 종류의 카드를 타입으로 나누고 데이터 배열(leads, sessionsRow1, sessionsRow2)로 캡슐화해서, 나중에 인원이 바뀌거나 늘어나도 배열에 항목만 추가하면 되도록 만들었습니다. 아직 실명이 확정되지 않아 role/name/dept 모두 placeholder 텍스트 상태입니다.

Blog 섹션: 무한 슬라이드

Blog 섹션은 고정 높이 칸 안에서 카드가 세로로 무한 슬라이드되는 효과를 구현했습니다. 카드 목록을 두 벌 복제해서 이어붙이고, translateY(-50%)에서 translateY(0)로 이동시켜 이음매 없이 반복되게 만드는 방식입니다.

.blog-track {
  animation-name: blog-marquee;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
.blog-viewport:hover .blog-track {
  animation-play-state: paused;
}

hover 시 정지되고 reduced-motion 환경에서는 애니메이션이 꺼지도록 처리해서, 페이지 전체 높이는 변하지 않으면서도 콘텐츠가 순환하는 느낌을 주도록 했습니다.

기술적 의사결정

왜 SVG 배경을 CSS data URI로?

여러 섹션(Thumbnail, Introduce, IntroduceSession, Members)의 배경 글로우가 Figma의 복잡한 radialGradient 값을 그대로 가져와야 했는데, 이를 별도 이미지 파일로 export하는 대신 CSS 안에 data:image/svg+xml 형태로 인라인했습니다. 덕분에 별도 네트워크 요청 없이 배경을 렌더링할 수 있고, gradientTransform matrix 값까지 Figma 원본 그대로 유지할 수 있었습니다.

커밋 흐름: 조립 → 규격 재조정

첫 커밋에서 전체 섹션을 한 번에 조립한 뒤, 두 번째 커밋(fix(fe): 세션·Members 섹션 배경/배치를 Figma 규격에 정확히 맞춤)에서 세션소개와 Members 섹션의 배경·배치를 다시 다듬었습니다. 커밋 메시지를 보면 세션소개 배경은 원래 고정 px·left 앵커로 짜여 있어서 뷰포트에 따라 좌우가 비대칭하게 보이는 문제가 있었고, 이를 %와 aspect-ratio로 환산해서 뷰포트 크기에 관계없이 일정하게 스케일되도록 고쳤습니다. Members도 컬럼 비율(580:380:390), gap, 카드 높이(221), 사진 크기(240×188, 174×188 등)를 Figma 수치에 맞춰 재조정했습니다. 처음에 조립부터 하고, 세부 수치는 다음 커밋에서 다듬어나간 흐름이 커밋 메시지에 그대로 드러납니다.

배운 점 및 개선점

Figma 시안의 절대 좌표를 반응형 웹으로 옮길 때 px을 그대로 쓰면 뷰포트가 바뀌는 순간 비율이 깨진다는 걸 체감한 작업이었습니다. % 환산과 aspect-ratio를 조합하는 패턴이 이번 PR 전반에 반복적으로 쓰였고, 이후 다른 섹션을 만들 때도 참고할 수 있는 기준이 될 것 같습니다.

아직 남은 과제도 명확합니다. 운영진 실명, 블로그 제목/날짜/썸네일 등은 전부 placeholder 상태라 PM·디자인 컨펌 후 실데이터 연동이 필요하고, #77 멤버 탭은 이번에 유지해둔 라우트 스텁을 기반으로 별도 페이지로 확장해야 합니다. 랜딩의 뼈대는 잡혔으니 다음 단계는 콘텐츠를 채우는 작업이 될 것 같습니다.