Skip to content

Commit

Permalink
Merge pull request #46 from pknu-wap/feature/#39-mainpage_card_list
Browse files Browse the repository at this point in the history
[feature] 메인페이지 카드 리스트 반응형 UI 및 필터링 추가
  • Loading branch information
oesnuj authored Feb 2, 2025
2 parents aa1523c + c4e0957 commit 558d9ec
Show file tree
Hide file tree
Showing 14 changed files with 405 additions and 45 deletions.
2 changes: 1 addition & 1 deletion frontend/config/webpack.common.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as path from 'path';
import * as webpack from 'webpack';
import * as HtmlWebpackPlugin from 'html-webpack-plugin';
const HtmlWebpackPlugin = require('html-webpack-plugin');

const configuration: webpack.Configuration = {
// 모듈 해석 방법 설정
Expand Down
2 changes: 1 addition & 1 deletion frontend/config/webpack.dev.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as path from 'path';
import * as webpack from 'webpack';
import { merge } from 'webpack-merge';
import * as RefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
const RefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
import 'webpack-dev-server';
import common from './webpack.common';

Expand Down
202 changes: 202 additions & 0 deletions frontend/src/apis/mockClubs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
export const mockClubs = [
{
id: '1',
name: '기독학생회',
logo: '/logos/club1.png',
tags: ['신앙', '친목'],
state: '모집중',
division: '중동',
classification: '종교',
description: '신앙 생활을 함께하는 클럽입니다.',
},
{
id: '2',
name: 'WAP',
logo: '/logos/club2.png',
tags: ['프로그래밍', '개발'],
state: '모집중',
division: '중동',
classification: '학술',
description: '프로그래밍을 배우고 프로젝트를 진행합니다.',
},
{
id: '3',
name: '축구 동아리',
logo: '/logos/club3.png',
tags: ['운동', '친목'],
state: '모집중',
division: '중동',
classification: '운동',
description: '축구를 즐기는 동아리입니다.',
},
{
id: '4',
name: '음악 동호회',
logo: '/logos/club4.png',
tags: ['공연', '밴드'],
state: '모집예정',
division: '중동',
classification: '공연',
description: '밴드 활동 및 공연을 진행합니다.',
},
{
id: '5',
name: '자원봉사팀',
logo: '/logos/club5.png',
tags: ['봉사', '사회활동'],
state: '모집중',
division: '중동',
classification: '봉사',
description: '지역사회 봉사를 위한 클럽입니다.',
},
{
id: '6',
name: '사진 동호회',
logo: '/logos/club6.png',
tags: ['사진', '취미'],
state: '모집마감',
division: '중동',
classification: '취미교양',
description: '사진 촬영 및 전시회를 개최하는 클럽입니다.',
},
{
id: '7',
name: '로봇 연구회',
logo: '/logos/club7.png',
tags: ['로봇', '공학'],
state: '모집중',
division: '중동',
classification: '학술',
description: '로봇을 연구하고 개발하는 클럽입니다.',
},
{
id: '8',
name: '헬스 동아리',
logo: '/logos/club8.png',
tags: ['헬스', '운동'],
state: '모집마감',
division: '중동',
classification: '운동',
description: '헬스를 통해 건강을 유지하는 클럽입니다.',
},
{
id: '9',
name: '프론트엔드 개발자 모임',
logo: '/logos/club9.png',
tags: ['프론트엔드', '개발'],
state: '모집중',
division: '중동',
classification: '학술',
description: '프론트엔드 기술을 공부하고 프로젝트를 진행합니다.',
},
{
id: '10',
name: '국제 교류 동아리',
logo: '/logos/club10.png',
tags: ['교류', '언어교환'],
state: '모집마감',
division: '중동',
classification: '취미교양',
description: '국제 학생들과의 문화 및 언어 교류 활동을 합니다.',
},
{
id: '11',
name: '드론 동아리',
logo: '/logos/club11.png',
tags: ['드론', '항공'],
state: '모집중',
division: '중동',
classification: '학술',
description: '드론 조종 및 항공 촬영을 배우는 클럽입니다.',
},
{
id: '12',
name: '요리 연구회',
logo: '/logos/club12.png',
tags: ['요리', '미식'],
state: '모집예정',
division: '중동',
classification: '취미교양',
description: '다양한 요리법을 연구하고 시연하는 클럽입니다.',
},
{
id: '13',
name: '연극 동아리',
logo: '/logos/club13.png',
tags: ['연극', '공연'],
state: '모집중',
division: '중동',
classification: '공연',
description: '연극 제작 및 공연을 통해 창의력을 발휘하는 클럽입니다.',
},
{
id: '14',
name: '환경 보호 동아리',
logo: '/logos/club14.png',
tags: ['환경', '보호'],
state: '모집마감',
division: '중동',
classification: '봉사',
description: '환경 보호 활동 및 캠페인을 진행하는 클럽입니다.',
},
{
id: '15',
name: '자전거 동호회',
logo: '/logos/club15.png',
tags: ['자전거', '여행'],
state: '모집중',
division: '중동',
classification: '운동',
description: '자전거 투어 및 관련 활동을 즐기는 클럽입니다.',
},
{
id: '16',
name: '애니메이션 제작 동아리',
logo: '/logos/club16.png',
tags: ['애니메이션', '영상'],
state: '모집예정',
division: '중동',
classification: '학술',
description: '애니메이션 제작 및 편집을 배우는 클럽입니다.',
},
{
id: '17',
name: '천체 관측 동아리',
logo: '/logos/club17.png',
tags: ['천문학', '관측'],
state: '모집중',
division: '중동',
classification: '학술',
description: '별과 행성을 관측하며 우주를 탐구하는 클럽입니다.',
},
{
id: '18',
name: '댄스 동아리',
logo: '/logos/club18.png',
tags: ['댄스', '퍼포먼스'],
state: '모집중',
division: '중동',
classification: '공연',
description: '다양한 댄스 장르를 배우고 공연하는 클럽입니다.',
},
{
id: '19',
name: '독서 토론 모임',
logo: '/logos/club19.png',
tags: ['독서', '토론'],
state: '모집마감',
division: '중동',
classification: '취미교양',
description: '책을 읽고 다양한 주제로 토론하는 클럽입니다.',
},
{
id: '20',
name: '비즈니스 전략 동아리',
logo: '/logos/club20.png',
tags: ['비즈니스', '전략'],
state: '모집중',
division: '중동',
classification: '학술',
description: '비즈니스 전략을 연구하고 실습하는 클럽입니다.',
},
];
52 changes: 52 additions & 0 deletions frontend/src/pages/MainPage/MainPage.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import styled from 'styled-components';

export const PageContainer = styled.div`
padding: 0 40px;
max-width: 1180px;
margin: 0 auto;
@media (max-width: 500px) {
padding: 0 20px;
}
@media (max-width: 375px) {
padding: 0 10px;
}
`;

export const ContentWrapper = styled.div`
width: 100%;
`;

export const CardList = styled.div`
display: grid;
width: 100%;
max-width: 100%;
gap: 20px;
margin-top: 50px;
transition:
gap 0.5s ease,
grid-template-columns 0.5s ease;
grid-template-columns: repeat(3, 1fr);
@media (max-width: 1280px) {
grid-template-columns: repeat(2, 1fr);
}
@media (max-width: 700px) {
grid-template-columns: repeat(1, 1fr);
}
@media (max-width: 500px) {
gap: 16px;
}
@media (max-width: 375px) {
gap: 10px;
}
`;

export const FilterWrapper = styled.div`
display: flex;
justify-content: right;
margin: 20px 0;
`;
53 changes: 47 additions & 6 deletions frontend/src/pages/MainPage/MainPage.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,61 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import CategoryButtonList from '@/pages/MainPage/components/CategoryButtonList/CategoryButtonList';
import ClubCard from '@/pages/MainPage/components/ClubCard/ClubCard';
import StatusRadioButton from '@/pages/MainPage/components/StatusRadioButton/StatusRadioButton';
import { mockClubs } from '@/apis/mockClubs';
import * as Styled from './MainPage.styles';
import Banner from '@/pages/MainPage/components/Banner/Banner';
import { BannerImageList } from '@/utils/banners';

const MainPage = () => {
const [selectedCategory, setSelectedCategory] = useState<string>('all');
const [isFilterActive, setIsFilterActive] = useState(false);
const [selectedCategory, setSelectedCategory] = useState('전체');
const [filteredClubs, setFilteredClubs] = useState(mockClubs);

const handleCategorySelect = (categoryId: string) => {
setSelectedCategory(categoryId);
const handleFilterChange = (status: boolean) => {
setIsFilterActive(status);
};

const handleCategorySelect = (category: string) => {
setSelectedCategory(category);
};

useEffect(() => {
let filtered = mockClubs;

if (isFilterActive) {
filtered = filtered.filter(
(club) => club.state === '모집중' || club.state === '모집예정',
);
}

if (selectedCategory !== '전체') {
filtered = filtered.filter(
(club) => club.classification === selectedCategory,
);
}

setFilteredClubs(filtered);
}, [isFilterActive, selectedCategory]);

return (
<>
<Styled.PageContainer>
<Banner banners={BannerImageList} />
<CategoryButtonList onCategorySelect={handleCategorySelect} />
</>
<Styled.FilterWrapper>
<StatusRadioButton onChange={handleFilterChange} />
</Styled.FilterWrapper>

<Styled.ContentWrapper>
<Styled.CardList>
{filteredClubs.length > 0 ? (
filteredClubs.map((club) => <ClubCard key={club.id} club={club} />)
) : (
<p>조건에 맞는 동아리가 없어요</p>
)}
</Styled.CardList>
</Styled.ContentWrapper>
</Styled.PageContainer>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,6 @@ export const CategoryButtonContainer = styled.div`
display: flex;
justify-content: space-between;
flex-wrap: nowrap;
@media (max-width: 1280px) {
gap: calc(5vw + 10px);
}
@media (max-width: 700px) {
gap: calc(4vw + 5px);
}
@media (max-width: 480px) {
gap: calc(3vw + 2px);
}
@media (max-width: 375px) {
gap: 8px;
}
`;

export const CategoryButton = styled.button`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const CategoryButtonList = ({ onCategorySelect }: CategoryButtonListProps) => {
{clubCategories.map((category) => (
<Styled.CategoryButton
key={category.id}
onClick={() => onCategorySelect(category.id)}>
onClick={() => onCategorySelect(category.name)}>
<img src={category.icon} alt={category.name} />
<span>{category.name}</span>
</Styled.CategoryButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const CardContainer = styled.div<{ state: string }>`
border-radius: 14px;
padding: 20px;
background-color: #fff;
width: 370px;
width: 100%;
height: 170px;
box-shadow: ${({ state }) =>
state === '모집중'
Expand Down Expand Up @@ -38,8 +38,10 @@ const TagsContainer = styled.div`

const Description = styled.p`
font-size: 0.875rem;
margin: 17px 3px 35px 5px;
margin: 22px 3px 22px 5px;
color: rgba(129, 129, 129, 1);
line-height: 16px;
white-space: nowrap;
`;

export {
Expand Down
Loading

0 comments on commit 558d9ec

Please sign in to comment.