Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] 메인페이지 카드 리스트 반응형 UI 및 필터링 추가 #46

Merged
merged 14 commits into from
Feb 2, 2025
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
seongwon030 marked this conversation as resolved.
Show resolved Hide resolved
@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,17 +1,58 @@
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';

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>
<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>
)}
seongwon030 marked this conversation as resolved.
Show resolved Hide resolved
</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;
}
`;
seongwon030 marked this conversation as resolved.
Show resolved Hide resolved

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