홍익대학교 축제 화양연화;PAGE 사이트입니다.
축제를 즐기는 학우들에게 축제 정보 제공을 목표로 하고 있습니다.
홍익대학교 총학생회 SEM;COLON과 협업하였습니다.
(2023년 프로젝트 이후로 해당 프로젝트가 다시 사용된다면 추가적으로 README 작성해주시면 되겠습니다.)
프론트엔드: React(JavaScript)
백엔드: Spring-Boot + Mysql(Spring boot JPA)
CI: Git
CD: GitHubActions + Docker
Infra: Aws Ec2, Rds
-
페이지별 기능의 경우 총학에서 요구하는 사항에 따라 년도별로 달라질 수 있음을 알립니다.
담당자 : 김진호 (jinhokim98)
-
랜딩
-
로드맵
-
라인업 소개
-
일정 소개
-
운영 시간
-
상단에 애니메이션 (gif)가 들어가며 그라데이션 효과가 적용되어있습니다.
-
아래로 스크롤하면 애니메이션이 블랙아웃되며 점점 사라집니다.
-
애니메이션 위로 2023 홍익대동제 화양연화 ; Page 화면이 덮습니다.
-
화양연화 화면이 고정되며 나머지 설명이 위로 올라옵니다.
-
학교 축제 내 위치들을 한 눈에 볼 수 있는 지도와 해당 위치 버튼이 있습니다.
-
전체, 수익부스, 무대, 홍익존, 주점, 푸트드럭, 기타 편의시설, 와우 디제이 페스티벌 구역이 있으며, 해당 버튼을 누르면 지도가 그에 맞게 변경됩니다.
-
지도의 핀을 누르게 되면 해당 페이지로 이동하게 됩니다.
-
9월 13, 14, 15일 3일로 구성되며, 각 칸에는 아티스트 사진과 설명이 들어옵니다.
-
사진 상단 좌우에 검은색 삼각형을 주어 포인트를 주었습니다 (뉴진스의 경우 사진 잘림 현상이 있어 제외)
-
차트맨과 함께한 아티스트는 문구를 넣어 사진 위에 강조했습니다.
-
펼치기 접기 기능을 만들어 라인업을 선택적으로 확인할 수 있습니다.
-
접기 기능을 할 때 라인업 펼치기 위치로 자동 스크롤 됩니다.
-
9.13, 14, 15일의 일정을 타임테이블로 보여주는 화면입니다.
-
이 기능을 통해 전체적으로 일정을 확인할 수 있습니다
-
각 운영 부스의 운영시간을 확인할 수 있습니다.
-
각 부스 별로 시간과 특이사항을 확인할 수 있습니다.
총학의 요구사항 변경이 정말 많았습니다.
전체적인 디자인부터 세부 내용 (특히 아티스트 소개 글, 시간)의 변동이 수도 없이 많았습니다.
전체적인 디자인 변경은 아직 프레임을 구성한 단계에서 일어나 무리 없이 대처할 수 있었지만. 그 뒤에 발생한 수정사항에 대해서는 대처하기 쉽지 않았습니다.
커밋을 한 후 반영을 할 때 바로 수정사항이 발생하여 다시 반영한 경우도 있었으며, 이동 중, 식당에 있는 도중에도 수정사항을 반영해달라는 요청이 있어, 그 자리에서 노트북을 열어 수정사항을 반영했을 정도로 요구사항 변화에 많이 시달렸습니다.
프론트 팀장님이 변경사항이 발생할 때마다 이를 정리하여 반영했음에도 너무 많은 수정사항이 발생하여 프론트 개발팀 사이에서도 혼동이 생겨 엉키는 문제도 발생했습니다.
커뮤니케이션을 통해 수정사항을 모두가 알고, 헷갈리지 않도록 해야한다는 것을 이번 프로젝트를 통해 몸으로 깨닫게 되었습니다.
- 상단 애니메이션 스크롤 문제
20px 스크롤 후 아래가 위를 덮는 효과를 넣는 것에 대한 고민이 많았습니다. 다른 개발자가 사용하고 있는 애니메이션 라이브러리인 aos로 해결해보고자 열심히 서치해봤지만 알맞은 것이 없어, 어떻게 구현해야할까 고민이 많았습니다.
그러다 현재 스크롤 값을 읽어와 각 컨테이너에 window.scrollY값을 주며 top 속성을 scrollY값에 따라 변화를 주고, 특정 scroll값에서 display: relative -> fixed로 처리했더니 원하는 결과를 얻을 수 있었습니다. 이후로 스크롤에 대한 effect를 활용할 때 이렇게 적용하면 된다는 것을 알게 되었습니다.
하지만 특정 기기에서 버벅임 이슈가 발생하여 조금 아쉬운 점이기도 합니다.
- 그림 로드 문제
그림이 용량이 커서 빠르게 로드되지 않아 뒷 배경이 보이는 문제가 생겼습니다.
이를 해결하기 위해 lazy loading이라는 기법을 찾아보게되었고, 이미지가 다 로드되었는지를 감지할 수 있는 IntersectionObserver JS api를 알게되었습니다.
이는 안에 있는 요소들이 다 준비가 되었는지를 판단할 수 있으며, 이를 활용하여 준비가 되지 않았을 때는 스켈레톤 이미지를 준비가 되면 이미지를 보여주는 기능을 넣을 수 있었습니다. IntersectionObserver api를 활용하여 이미지가 준비되었는지를 판단하는 커스텀 훅을 아래에 올립니다.
import { useState, useEffect } from 'react';
/**
* useLazyLoading
*
* 로딩 중이면 스켈레톤 이미지, 아니면 실제 이미지를 보여주는 것을 판단해주는 custom hook
* @param observerRef 이미지를 포함하는 ref
* @returns loading 로딩 중 boolean
*/
function useLazyLoading(observerRef) {
const [loading, setLoading] = useState(true);
let observer = null;
useEffect(() => {
if (observerRef.current && loading) {
observer = new IntersectionObserver(([entries]) => {
if (entries.isIntersecting) {
setLoading(false);
}
});
observer.observe(observerRef.current);
}
return () => {
if (observer) {
observer.disconnect(observerRef);
}
};
}, [loading, observerRef]);
return loading;
}
export default useLazyLoading;
- 반응형 문제
많은 사람들이 쓰는 화면이고, 사람들마다 기기가 천차만별로 다르기 때문에 프로젝트에 반응형 적용은 필수였습니다. 때문에 모든 size를 rem으로 변환하여 적용을 했습니다.
또한 미디어쿼리로 450 600 그 이상을 나누어 font-size: 10, 13, 16으로 주었고, 이를 따라서 다른 모든 크기 요소를 rem으로 적용하니 450px이상이 되면 자동으로 모든 요소가 커지고 작아지면 작아지는 효과를 볼 수 있었습니다.
- 그림 내 마커 문제
그림안에 마커를 넣고 마커를 클릭하면 이동하는 이벤트를 구현할 때의 이슈입니다.
그림이 가만히 있으면 문제가 없지만, 모든 사람들의 기기의 너비가 다르고, 450, 600px일 때마다 사이즈가 커지므로 그림의 크기가 달라질 수 밖에 없었습니다.
처음에 그냥 top, left로 조정해보려했지만 너비가 달라지면 마커의 위치가 달라져 원하는 곳에 마커가 위치할 수 없던 문제가 있었습니다.그림이 커지거나 작아질 때 마커가 그에 맞추어 따라가게 하는 방법에 대해 열심히 조사를 해봤습니다.
해결 방법은 top과 left속성을 단순 rem으로 하는 것이 아니라 calc(50% - 1.2rem)이런 식으로 적용을 하면 그림이 커지거나 작아져도 마커가 그 위치를 지킬 수 있다는 것을 알게되었고, 이를 적용하여 성공적으로 지도 위에 마커를 배치할 수 있었습니다.
- width 100%에 대한 고찰
부모가 100%가 되어있지 않으면 자식들이 부모의 크기를 넘어서는 경우가 생겨, 엉뚱한 컴포넌트가 잘못 적용되었다고 오해를 한 상황이 발생했습니다.
꼭 부모를 100%로 적용해주어 자식이 이를 넘어서는 일이 발생하지 않도록 해야한다는 것을 알게 되었습니다.
-
상단 애니메이션 특정 기기에서의 스크롤 문제
-
스켈레톤 이미지마저 간헐적으로 늦게 로딩되는 현상
담당자 : 계용운 (yongun2)
- 팔찌 부스 정보 제공
- 연예인 라인업 소개
- 요일별 중앙무대 라인업 소개
- 홍익존 팔찌를 배부하는 부스의 위치, 시간 정보 제공
- 위치 정보의 경우 지도 이미지, 시간 정보의 경우 Card 형태로 제공
- 요일별 연예인 라인업 소개
- 디자이너 님께서 만들어주신 이미지를 사용하였습니다.
- 요일별 중앙무대 라인업 소개
- Day1 ~ Day3 으로 구분하여 슬라이드 또는 요일을 눌렀을 때 해당 요일의 라인업을 출력합니다.
TimeTable.jsx 참고
현재 스케줄 슬라이드 기능은 react-slick 이라는 라이브러리를 사용하여 구현하였습니다.
Slide 컴포넌트는 children으로 넘어온 컴포넌트 쌍 들을 옵션값 rows 따라서 slice 하고 슬라이드 마다 출력합니다. 따라서 옵션값에서 rows를 Day1 ~ Day3 중에서 max(row)에 해당하는 값으로 세팅해주어야 합니다.
주의 : max(row) 만큼 일정이 존재하지 않을 경우 더미 데이터를 넣어 개수를 맞춰주어야 합니다. 그러지 않을 경우 모든 시간대가 한 슬라이드 내에 출력되지 않습니다.
예시)
/** react slick 옵션 */
const settings = {
dots: false,
arrows: false,
rows: 4,
fade: true,
};
[
{
type: 'hongikCentral',
stage: '학생중앙무대',
time: '17:00 ~ 20:10',
details: [
'조용찬',
'캐드',
'오픈런',
'강은서밴드',
'소리얼',
'오현성콰트로치즈와퍼',
'브레인스워즈',
'비츠플로우',
],
},
{
type: 'celab',
stage: '연예인 초청무대',
time: '20:10 ~ 22:20',
details: ['NewJeans', '정용화', '이승윤', '릴보이'],
},
{ type: '', stage: '', details: [] }, // 더미 데이터
{ type: '', stage: '', details: [] },
],
현재 스와이프 관련 로직과, 현재 날짜를 계산하여 timetable의 Day를 계산하는 로직이 CentralState.jsx 컴포넌트 내에 존재합니다. 이러한 로직들을 useDay, useSwipe와 같은 커스텀 훅을 만들어 컴포넌트와 분리한다면 더 깔끔하고 유지보수에 도움이 될 것 같습니다.
담당자 : 계용운 (yongun2)
-
수익부스 위치 안내
-
수익부스 판매 정보 제공
-
핀을 누를 경우 해당 위치로 스크롤
-
관리자 권한
- 수익부스 카드 CRUD
- 수익 부스의 위치를 지도 이미지와 핀을 통해 제공합니다.
- 수익 부스의 이름, 주최자, 소개글을 제공합니다.
- 위치 지도상에 있는 핀을 누를 경우 해당하는 수익부스 안내 카드로 스크롤 됩니다.
- 관리자로 로그인할 경우 수익부스 정보에 대한 CRUD 가능
개발 초반 ~ 중반까지 수익부스, 프로모션 부스, 주점 페이지에서 사용되는 Card의 디자인이 동일하였고 노출되는 정보의 종류 역시 동일하였기 때문에 BlackCard 라는 동일한 컴포넌트를 사용하여 개발을 진행 하였습니다.
하지만 개발 막바지에 각 페이지의 디자인이 변경되었고, Card에 출력되는 정보 역시 각 페이지별로 달라졌습니다. 따라서 공통으로 사용하던 BlackCard 컴포넌트를 결국 사용하지 못하게 되고 각 페이지에 해당하는 Card 컴포넌트를 만들었습니다.
수익 부스 카드와 프로모션 카드의 경우 전체적으로 같은 디자인을 가지고 있고 일부 정보의 유무와 같은 아주 작은 차이점만 존재합니다.
[수익 부스 카드]
[프모모션 부스 카드]
하지만 현재 ProfitBoothCard.jsx, PromotionBoothCard.jsx와 같이 페이지별로 카드 컴포넌트를 만들었기 때문에 두 컴포넌트의 코드를 보면 매우 비슷하고, 중복되는 코드가 존재합니다.
이러한 문제를 BoothCard라는 compound components를 사용하여 중복되는 코드를 줄이고 새로운 디자인에 대한 컴포넌트를 자식 컴포넌트로 만들어 유지 보수와 변화하는 요구사항에 조금 더 유연하게 대처할 수 있었을 것 같습니다.
담당자 : 계용운 (yongun2)
- 프로모션 부스 위치 안내
- 프로모션 부스 정보 제공
- 핀을 누르면 해당 위치로 스크롤
- 수익 부스와 동일하게 위치를 지도 이미지와 핀을 통해 제공합니다.
- 수익 부스의 이름, 운영 요일 정보를 제공합니다.
- 위치 지도상에 있는 핀을 누를 경우 해당하는 수익부스 안내 카드로 스크롤 됩니다.
시작: 2023년 8월 8일
종료: 2023년 9월 12일
- 계용운
- 김진호
- 김현민
- 김초연
- 원윤서