세붕이 웹 홈페이지를 마치고…
프로젝트 소개
세붕이 웹 홈페이지는 내가 현재 활동하고 있는 세명컴퓨터고등학교 세붕이의 웹사이트를 만드는 프로젝트로 내가 처음으로 진행한 웹 프로젝트이다.
- 플랫폼 : WEB
- 사용 기술 : JavaScript, NEXT.js, Tailwind CSS, Tailblocks, Notion Database
- 진행 기간: 2023.03.31 ~ 2023.04.05 (5일)
- 진행 인원: 개인 프로젝트 (1인)
- 깃허브 리포지토리
개발 배경
사실 해당 프로젝트는 2022년도에 2학년 선배들이 링크드인처럼 만들려던 프로젝트였지만 프론트 담당이 없어 기능 구현만 하다가 프로젝트가 1차로 틀어졌고 2023년이 되어 선배들이 1학년 후배들에게 시켜 또 흐지부지 되려던 계획을
이렇게 또 흐지브지 되서 없어질 바에는 차라리 내가 웹을 배워서 기초적으로 완성하고 내년 후배들이 웹을 배워서 업그레이드 시키는게 낫겠다는 생각으로 총대를 매고 시작하게 된 프로젝트이다.
사용 예제
사진
웹사이트의 모습은 위와 같다.
구현 기능
- 프로젝트
- 세붕이 멤버들이 진행한 프로젝트를 종류 별로 보여주는 기능 (ALL, iOS, Android, WEB)
- 태그로 해당 프로젝트의 종류와 어떤 멤버가 진행했는 지 보여주는 기능
- 해당 프로젝트 클릭 시 해당 프로젝트 깃허브로 이동시키는 기능
- 멤버
- 세붕이 멤버들을 재학과 졸업으로 구분하여 보여주는 기능
- 세붕이 멤버들의 프로필 사진과 짧은 코멘트, 분야를 보여주는 기능
- 해당 멤버들의 연관 사이트로 이동시키는 기능 (깃허브 주소, 인스타 주소, 블로그 주소)
- 멤버 활동
- 세붕이 멤버들의 멤버 활동들을 종류 별로 보여주는 기능 (ALL, 대회, 세미나)
- 세붕이 멤버들의 활동들을 활동명과 사진, 진행 멤버 및 순위를 보여주는 기능
이슈
대회 및 세미나 갯수 필터링 문제
코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
export default function Activity({activity}) {
const n = "\n"
const [selectedActivity, setSelectedActivity] = useState(3);
const filteredActivity = activity.filter(activity => {
const type = activity.properties.타입.number;
return selectedActivity === 3 || type === selectedActivity;
});
const count0 = filteredActivity.filter(activity => activity.properties.타입.number === 0).length;
const count1 = filteredActivity.filter(activity => activity.properties.타입.number === 1).length;
return (
<Layout>
...
<section className="flex min-h-screen flex-col justify-center text-gray-600 body-font mb-0">
<div className="container mx-auto px-5 py-24 md:flex-row flex-col items-start">
<div className="flex items-center justify-between4">
<div className="ml-5 text-2xl whitespace-pre-line leading-snug font-medium break-keep"><span className="text-6xl font-black text-sky-500">세붕이 멤버활동{n}{n}</span>성장에 대한 열정을 가진 저희 <span className="text-blue-500 font-bold">세붕이 멤버들은</span> 지금까지 <span className="text-blue-500 font-bold">{count0}개의 외부 대회</span>에서 수상을 하였고 세붕이 자체적으로 세미나를 개최하여 <span className="text-blue-500 font-bold">총 {count1}개의 세미나를 성공적으로</span> 진행했습니다!</div>
<Animation />
</div>
<div className="flex justify-start w-full max-w-lg items-start">
<button
className={`ml-5 flex items-center justify-center w-1/4 h-12 rounded-full border ${
selectedActivity === 3
? 'bg-blue-500 text-white'
: 'border-gray-300 text-gray-500'
} mr-4 hover:bg-blue-500 hover:text-white transition-all duration-500 `}
onClick={() => setSelectedActivity(3)}
>
<h2 className="text-lg font-medium">ALL</h2>
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-3">
{filteredActivity.map(activity => (
<ActivityItem key={activity.id} activity={activity} />
))}
</div>
</div>
</section>
</Layout>
);
}
내가 처음에 구상한 로직으로는 위와 같이 데이터베이스의 저장된 세미나와 프로젝트의 수를 유동적으로 보여주게 하는 것을 하고 싶었다 그렇게 잘 되는 것처럼 보였으나…
ALL 상태일 때는 괜찮았으나 세미나, 프로젝트를 선택해서 그것만 보여주려고 하니 이렇게 선택되지 않는 태그에 것들은 0으로 바뀌는 문제가 생겼다 해당 문제를 해결하려고 다양한 방법을 시도해봤는데
시도 1
1
2
3
const count0 = selectedActivity === 3 ? filteredActivity.length : filteredActivity.filter(activity => activity.properties.타입.number === 0).length;
const count1 = selectedActivity === 3 ? filteredActivity.length : filteredActivity.filter(activity => activity.properties.타입.number === 1).length;
아닐 거 같지만 혹시나?하고 count부분을 이렇게 수정 해봤지만 역시나
당연하게도 실패 오히려 기본 상태일 때도 이상하게 바뀌었고
시도 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
export default function Activity({activity}) {
const n = "\n"
const [selectedActivity, setSelectedActivity] = useState(3);
const filteredActivity = activity.filter(activity => {
const type = activity.properties.타입.number;
return selectedActivity === 3 || type === selectedActivity;
});
const count0 = filteredActivity.filter(activity => activity.properties.타입.number === 0).length;
const count1 = filteredActivity.filter(activity => activity.properties.타입.number === 1).length;
const arr = [["세붕이 멤버활동\n\n","저희 ","세붕이 멤버들은"," 지금까지",` ${count0}개의 외부 대회`,"에 참여하여 수상을 하였습니다"],["세붕이 멤버활동\n\n","저희 ","세붕이 멤버들은"," 지금까지",` ${count1}개의 세미나`,"를 자체적으로 개최하여 성공적으로 진행했습니다"],[],["세붕이 멤버활동\n\n","성장에 대한 열정을 가진 저희 ","세붕이 멤버들은"," 지금까지",` ${count0}개의 외부 대회`,"에서 수상을 하였고 세붕이 자체적으로 세미나를 개최하여 ",`총 ${count1}개의 세미나`,"를 성공적으로 진행했습니다!"]]
return (
<Layout>
...
<section className="flex min-h-screen flex-col justify-center text-gray-600 body-font mb-0">
<div className="container mx-auto px-5 py-24 md:flex-row flex-col items-start">
<div className="flex items-center justify-between4">
<div className="ml-5 text-2xl whitespace-pre-line leading-snug font-medium break-keep"><span className="text-6xl font-black text-sky-500">{arr[selectedActivity][0]}</span>{arr[selectedActivity][1]}<span className="text-blue-500 font-bold">{arr[selectedActivity][2]}</span>{arr[selectedActivity][3]}<span className="text-blue-500 font-bold">{arr[selectedActivity][4]}</span>{arr[selectedActivity][5]}<span className="text-blue-500 font-bold">{arr[selectedActivity][6]}</span>{arr[selectedActivity][7]}</div>
<Animation />
</div>
<div className="flex justify-start w-full max-w-lg items-start">
<button
className={`ml-5 flex items-center justify-center w-1/4 h-12 rounded-full border ${
selectedActivity === 3
? 'bg-blue-500 text-white'
: 'border-gray-300 text-gray-500'
} mr-4 hover:bg-blue-500 hover:text-white transition-all duration-500 `}
onClick={() => setSelectedActivity(3)}
>
<h2 className="text-lg font-medium">ALL</h2>
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-3">
{filteredActivity.map(activity => (
<ActivityItem key={activity.id} activity={activity} />
))}
</div>
</div>
</section>
</Layout>
);
}
두번째 시도에서는 로직을 바꿔서 아예 해당하는 태그에 글만 보여주는 것으로 바꿔서 구현을 해봤다.
하지만 무언가 허전하는 느낌을 지울 수 없고 마지막으로 해결책을 찾다가 시도한 것이
1
2
const count0 = useRef(filteredActivity.filter(activity => activity.properties.타입.number === 0).length);
const count1 = useRef(filteredActivity.filter(activity => activity.properties.타입.number === 1).length);
useRef로 useRef를 사용하여 컴포넌트의 렌더링과 관련없이 변수를 유지하게 만들어서 아래와 같이
내가 원하던 대로 처음 구상하던 로직을 구현할 수 있었다.
느낀점
해당 프로젝트는 솔직히 말해서 매우 하기 싫었던 프로젝트로 어쩔 수 없이 맡았서 진행했다 이미 한번 선배들이 하다가 엎어졌던 프로젝트기도 하고 선배들이 1학년들에게 맡겼다가 또 한번 엎어질 위기인 상태라 어쩔 수 없이 한명이 책임져서 멱살 끌고 진행하지 않으면
진행이 안되다가 사라질 거 같아서 위에서 말했던 것처럼 그냥 일단 내가 배워서 웹을 기초만 만들고 미래의 후배들이 웹을 배우면 그 때 가서 새로 만들거나 업그레이드 하자라는 생각으로 진행했었다.
이런 마음으로 프로젝트를 진행하고 제일 처음 시작한 것은 웹에 대해 배우기 시작한 것이였는데 나는 웹에 대해 전혀 몰랐기 때문에 강의와 책을 보고 배우면서 진행했었다 하지만 웹을 기초부터 배우니 정말… 공부가 하기 싫어지고 그냥 프로젝트를 도중에 때려치고 싶을 정도로 현타가 왔었다.
그러니 이렇게 포기할바에는 “일단 구현부터 시작해보자”라는 생각으로 일단 시작했다 이렇게 프로젝트를 시작하면서 여러가지 툴에 도움을 받았는데 그것들이 바로 Tailblocks, Tailwind CSS, chatGPT 이다 그중에서 Tailblocks와 Tailwind CSS로 내가 제일 못하는 웹 프론트 UI 부분을 빠르게 개발할 수 있었고 로직을 개발하거나 외부에서 라이브러리나 코드를 가져와 사용할 때 chatGPT를 통해 큰 도움을 받았다.
이 세 개의 툴들이 없었다면 이렇게 빠른 시간내에 웹 프론트 초보자인 내가 개발을 하지 못했을 거라 생각한다 여기서 사용한 도구 중 특히 chatGPT는 맞지 않는 코드를 내뱉는 경우도 많았지만 외부에서 가져온 코드나 라이브러리를 해석할 때 매우 크게 도움을 받을 수 있었다 그래서 앱 개발할 때도 사용해보려고 하는데 다만 코드까지 chatGPT에 의존하여 개발하는 것은 실력이 늘지 않는다고 생각하기에 정말 해석이 안되거나 모르는 코드들이나 라이브러리에 대해 정보를 얻을 때 최후로만 사용할 예정이다.