diff --git a/src/app/project/page.tsx b/src/app/project/page.tsx
index b7b7ed9..f691bfe 100644
--- a/src/app/project/page.tsx
+++ b/src/app/project/page.tsx
@@ -1,11 +1,219 @@
-export default function ProjectPage() {
+// [Next.js 문법] 'use client'는 이 컴포넌트가 브라우저에서 상호작용(useState, 클릭 등)을 한다는 것을 Next.js에 알림
+'use client';
+
+import { useState } from 'react';
+
+// --- (7주차 추가: 공통 컴포넌트 추출 - 프로젝트 리스트 아이템) ---
+// [자바스크립트/React] 독립적인 UI 단위를 함수로 만든 '컴포넌트' 파트
+function ProjectRow({
+ status,
+ position,
+ title,
+ author,
+ time,
+ comments
+}: {
+ status: string;
+ position: string;
+ title: string;
+ author: string;
+ time: string;
+ comments?: number;
+}) {
+ // [자바스크립트 문법] 변수 선언 및 조건식(비교 연산)
+ const isCompleted = status === '완료'; // isCompleted 안에 불리언(true/false) 값 저장
+ // // 1번째 함수 (재사용 가능한 UI 조각)
return (
-
- 프로젝트 모집
-
- 팀 프로젝트 모집 게시판이 준비 중입니다. 곧 더 많은 콘텐츠를 확인할 수 있어요.
-
-
+
+ {/* [반응형 레이아웃 1] 모바일 카드형 (sm 미만에서 표시, sm 이상에서 hidden) */}
+
+ {/* 상단: 상태 및 포지션 배지 영역 */}
+
+ {/* [자바스크립트 문법] 템플릿 리터럴(` `)과 삼항 연산자를 사용한 동적 클래스 부여 */}
+
+ {status}
+
+
+ {position}
+
+
+
+ {/* 하단: 제목(왼쪽 정렬)과 작성자/시간(오른쪽 정렬) */}
+
+
+ {title}
+ {/* [자바스크립트 문법] && (단락 평가): comments가 있을 때만 💬 아이콘 렌더링 */}
+ {comments && 💬 {comments}}
+
+
+ {/* 작성자 및 업로드 시간을 세로로 배치 */}
+
+ {author}
+ {time}
+
+
+
+
+ {/* [반응형 레이아웃 2] 태블릿/PC 그리드형 (sm 이상에서 표시, sm 미만에서 hidden) */}
+
+
+
+ {status}
+
+
+
+
+ {position}
+
+
+
+ {title}
+ {comments && 💬 {comments}}
+
+
{author}
+
{time}
+
+
);
}
+// [Next.js 문법] export default는 이 파일을 특정 주소(URL)로 접속했을 때 보여줄 '페이지'로 지정
+export default function ProjectPage() {
+
+ // [자바스크립트/React 문법] 상태 관리 (State)
+ const [currentPage, setCurrentPage] = useState(1); // 현재 페이지네이션 번호
+ const [selectedPosition, setSelectedPosition] = useState('전체'); // 현재 선택된 포지션 필터
+ const [selectedStatus, setSelectedStatus] = useState('모집 중'); // 현재 선택된 모집 여부 필터
+
+ // [자바스크립트 문법] 상수 데이터 배열 정의
+ const positions = ['전체', '프론트엔드', '백엔드', '개발', '디자인', '기획', '기타'];
+ const totalPages = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+
+ // --- (새로운 기능: 클릭 이벤트 핸들러) ---
+ // [자바스크립트 문법] 화살표 함수를 사용하여 클릭 시 상태 변경과 콘솔 기록을 동시에 수행
+ const handlePositionClick = (pos: string) => {
+ setSelectedPosition(pos);
+ console.log(`선택된 포지션: ${pos}`); // 브라우저 개발자 도구 콘솔에 기록
+ };
+
+ const handleStatusClick = (status: string) => {
+ setSelectedStatus(status);
+ console.log(`선택된 모집 상태: ${status}`);
+ };
+ // 2번째 함수 (전체 페이지)
+ return (
+
+ {/* [메인 영역] pt-64: 모바일에서 길어진 헤더 높이만큼 상단 여백(Padding-Top)을 충분히 확보 */}
+
+
+ {/* [1] 필터 구역 */}
+
+
+
+ {/* 1-1. 구인 포지션 필터 (모바일에서는 세로 레이아웃) */}
+
+
+ 구인 포지션
+
+
+ {/* [자바스크립트 문법] .map()을 사용하여 배열 데이터만큼 버튼 생성 */}
+ {positions.map((pos) => (
+
+ ))}
+
+
+
+ {/* 1-2. 모집 여부 필터 */}
+
+
+ 모집 여부
+
+
+ {/* [자바스크립트 문법] 즉석에서 생성한 배열(['모집 중', '완료'])로 map 실행 */}
+ {['모집 중', '완료'].map((st) => (
+
+ ))}
+
+
+
+
+
+ {/* [2] 리스트 구역 */}
+
+ {/* 리스트 헤더: sm(640px) 이상 화면에서만 보이도록 설정 */}
+
+
여부
+
포지션
+
프로젝트 모집 글
+
작성자
+
업로드 시간
+
+
+ {/* [자바스크립트/React] 사용자 정의 컴포넌트 ProjectRow에 데이터를 전달(Props) */}
+
+
+
+
+
+
+
+
+ {/* [3] 페이지네이션 */}
+
+
+ {totalPages.map((num) => (
+
+ ))}
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/app/study/page.tsx b/src/app/study/page.tsx
index 09438d2..e49ee1c 100644
--- a/src/app/study/page.tsx
+++ b/src/app/study/page.tsx
@@ -1,11 +1,160 @@
-export default function StudyPage() {
+// [Next.js 문법] 'use client'는 클라이언트 사이드 렌더링을 명시하는 Next.js 전용 지시어
+'use client';
+
+import { useState } from 'react';
+
+// 1. 카드 컴포넌트 (일반 React/JS 함수형 컴포넌트)
+function StudyCard({ number }: { number: number }) {
return (
-
- 스터디 모집
-
- 진행 중인 스터디 모집 공지와 신청 폼이 곧 업데이트될 예정입니다.
-
-
+
);
}
+// [Next.js 문법] export default 함수는 해당 파일의 대표 페이지가 됩니다. (App Router 라우팅)
+export default function StudyPage() { //라우팅 경로에 맞게 함수명 변경
+
+ // [자바스크립트/React 문법] 상태 관리를 위한 Hook 사용
+ const [selected, setSelected] = useState('전체');
+ const [status, setStatus] = useState('모집 중');
+ const [currentPage, setCurrentPage] = useState(1);
+
+ // [자바스크립트 문법] 변수 및 배열 선언
+ const categories = ['전체', 'C', 'Python', 'Java', '알고리즘', "기타"];
+ const totalPages = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+
+ // --- (7주차 추가 시작 : 콘솔로그 - 자바스크립트 로직 파트) ---
+ // 카테고리 클릭 시 실행될 함수
+ const handleCategoryClick = (category: string) => {
+ setSelected(category);
+ console.log(`선택된 카테고리: ${category}`); // 개별적인 이벤트 로그
+ };
+
+ // 모집 상태 클릭 시 실행될 함수
+ const handleStatusClick = (statusName: string) => {
+ setStatus(statusName);
+ // 모집 중이면 true, 모집 완료면 false
+ const isRecruiting = statusName === '모집 중'; // 왼쪽 값과 오른쪽 값을 비교하여 결과를 무조건 불리언
+
+ // false(모집 완료)일 때만 콘솔에 찍기
+ if (!isRecruiting) {
+ console.log(`모집 상태: ${isRecruiting}`);
+ }
+ };
+ // --- (7주차 추가 끝 : 콘솔로그) ---
+
+ return (
+ // (7주차 수정) 전체 화면 너비를 차지하는 배경 레이어 추가 -> 사이드 검둥이 제거
+
+
+
+ {/* 1번 네모: 제목 */}
+
+
스터디 모집 공고
+
+
+ {/* 2번 네모: 필터 구역 (7주차 수정: 반응형 레이아웃 적용) */}
+
+ {/* !!!!(7주차 수정) flex-col로 세로 정렬하되, md: 768px 이상에서만 가로(row) 정렬, items-start로 왼쪽 정렬 */}
+
+ {/* 카테고리 버튼 구역 (7주차 수정: 줄바꿈 허용) */}
+
+ {/* (7주차 추가) flex-wrap을 넣어 화면이 좁아지면 버튼이 다음 줄로 넘어가게 함 */}
+ {/* [자바스크립트 문법] .map()을 사용하여 배열 데이터를 JSX 리스트로 변환 JSX 안의 {} 사용*/}
+ {categories.map((category) => (
+
+ ))}
+
+
+ {/* 모집 상태 버튼 구역 (7주차 수정: 모바일 환경에서는 숨기고 데스크톱에서만 표시) */}
+
+ {/* (7주차 수정) 'hidden'으로 기본 숨김 처리, 'md:flex'로 768px 이상에서만 나타나게 함 -> 모바일 환경 우선*/}
+
+
+
+
+
+ {/* 3번 네모: 카드 그리드 */}
+ {/*카드의 반응형을 담당하는 핵심 코드*/}
+ {/* [자바스크립트 문법] 빈 배열을 생성하여 반복 렌더링 수행 */}
+ {[...Array(9)].map((_, i) => (
+
+ ))}
+
+
+ {/* 4번 네모: 페이지네이션 */}
+
+ {/* [자바스크립트 문법] 화살표 함수와 Math 객체를 활용한 로직 처리 */}
+
+
+ {totalPages.map((num) => (
+
+ ))}
+
+
+
+
+
+ );
+}
\ No newline at end of file