-
Notifications
You must be signed in to change notification settings - Fork 3
[feature] 동아리 클릭 배틀 게임 페이지 #1471
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
Merged
Merged
Changes from 11 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
3a611a4
feat(game): game 타입, API, React Query 훅 추가
seongwon030 6c2345e
feat(game): /game 라우트 추가 및 MSW 핸들러 정리
seongwon030 1cd039a
feat(game): GamePage 레이아웃 구현 (타이틀 중앙, 순위 우측, 버튼 하단)
seongwon030 e37f748
feat(game): DotTextEffect 컴포넌트 구현 (dot 색상 ripple, 랜덤 색상)
seongwon030 9b4297b
feat(game): ClickButton, ClubNameInput, RankingBoard 컴포넌트 구현
seongwon030 765ddec
docs(game): GamePage 기능 문서 추가
seongwon030 cd420e4
fix: 예시 텍스트 변경
seongwon030 8473546
feat(game): ClubNameInput 동아리명 자동완성 및 유효성 검사 추가
seongwon030 f906c6a
refactor: 데탑, 모바일 배치 변경
seongwon030 bd8245f
refactor: dot글자부분 상단으로 올림
seongwon030 bb6f383
refactor(game): 모바일 UX 개선 - DotTextEffect 터치/성능/크기, ClubNameInput 반응형
seongwon030 63044fb
fix(game): handleResponse 비-null 단언 제거 및 charColors 상수화
seongwon030 28dcf2d
refactor(game): ClubNameInput 자동완성 race condition 수정
seongwon030 9990176
feat(game): ClubNameInput 자동완성 키보드 접근성 추가
seongwon030 3876310
fix(game): RankingBoard 로딩 중 잘못된 초기화 시간 노출 수정
seongwon030 8b38b64
fix(game): DotTextEffect canvas 접근성 개선 - role 및 aria-label 추가
seongwon030 0e882d3
fix(game): DotTextEffect 뷰포트 리사이즈 시 폰트 크기 미반영 버그 수정
seongwon030 510c63e
refactor(game): ClubNameInput 제출 검증을 React Query 캐시 경로로 통합
seongwon030 0dd4243
refactor(game): 클릭 카운트를 서버 응답 대신 클라이언트에서 직접 누적
seongwon030 8fcdd1f
fix(game): ClubNameInput 드롭다운 재오픈 및 DotTextEffect 리사이즈 scale 버그 수정
seongwon030 1aca543
feat: mutation에 에러 콘솔 추가
seongwon030 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # GamePage 레이아웃 및 DotTextEffect 인터랙션 개선 | ||
|
|
||
| ## 레이아웃 구조 | ||
|
|
||
| `TopRow`를 3-column grid(`1fr auto 1fr`)로 구성하여 타이틀을 절대 중앙에 고정하고 순위표를 오른쪽 끝에 배치. | ||
| DotTextEffect는 전체 너비 가운데, 클릭 버튼은 하단(`marginTop: 40px`)에 위치. | ||
|
|
||
| ``` | ||
| ┌─────────────────────────────────────────────┐ | ||
| │ [빈 공간] 동아리 클릭 배틀 [실시간 순위] │ | ||
| │ │ | ||
| │ [ 개 발 팀 (DotText) ] │ | ||
| │ │ | ||
| │ [클릭! 버튼] │ | ||
| └─────────────────────────────────────────────┘ | ||
| ``` | ||
|
|
||
| ## DotTextEffect 색상 Ripple | ||
|
|
||
| 마우스 커서 주변 `colorRadius(= hoverRadius * 1.8)` 범위 내 dot들이 거리 비례로 색상이 물드는 효과. | ||
|
|
||
| - 파워 커브 `Math.pow(dist / colorRadius, 2.5)` 적용 → 중심만 진하고 바깥은 급격히 회색으로 | ||
| - 각 dot에 `charColors` 중 랜덤 색상 미리 배정 (글자 단위 → dot 단위 랜덤) | ||
| - `hoverRadius: 18`, `dotR: 1.8` (겹침 방지) | ||
|
|
||
| ## 관련 코드 | ||
|
|
||
| - `src/pages/GamePage/GamePage.tsx` — 레이아웃 구조 (TopRow, DotTextEffect 중앙, 버튼 하단) | ||
| - `src/pages/GamePage/GamePage.styles.ts` — TopRow grid 스타일 | ||
| - `src/pages/GamePage/components/DotTextEffect/DotTextEffect.tsx` — 색상 ripple 및 랜덤 색상 로직 | ||
| - `src/pages/GamePage/components/RankingBoard/RankingBoard.styles.ts` — Header column 방향 변경 | ||
| - `src/pages/GamePage/components/ClickButton/ClickButton.styles.ts` — ClubLabel 말줄임 처리 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import API_BASE_URL from '@/constants/api'; | ||
| import { GameClickResponse, GameRankingResponse } from '@/types/game'; | ||
| import { handleResponse } from './utils/apiHelpers'; | ||
|
|
||
| export const postGameClick = async ( | ||
| clubName: string, | ||
| ): Promise<GameClickResponse> => { | ||
| const response = await fetch(`${API_BASE_URL}/api/game/click`, { | ||
| method: 'POST', | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| body: JSON.stringify({ clubName, ctAt: new Date().toISOString() }), | ||
| }); | ||
|
seongwon030 marked this conversation as resolved.
|
||
| const data = await handleResponse<GameClickResponse>( | ||
| response, | ||
| '클릭 요청에 실패했습니다.', | ||
| ); | ||
| return data!; | ||
|
seongwon030 marked this conversation as resolved.
Outdated
|
||
| }; | ||
|
|
||
| export const getGameRanking = async (): Promise<GameRankingResponse> => { | ||
| const response = await fetch(`${API_BASE_URL}/api/game/ranking`); | ||
| const data = await handleResponse<GameRankingResponse>( | ||
| response, | ||
| '랭킹을 불러오는데 실패했습니다.', | ||
| ); | ||
| return data!; | ||
| }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import { useMutation, useQuery } from '@tanstack/react-query'; | ||
| import { getGameRanking, postGameClick } from '@/apis/game'; | ||
| import { queryKeys } from '@/constants/queryKeys'; | ||
|
|
||
| export const useGameRanking = () => { | ||
| return useQuery({ | ||
| queryKey: queryKeys.game.ranking(), | ||
| queryFn: getGameRanking, | ||
| refetchInterval: 2000, | ||
| staleTime: 0, | ||
| }); | ||
| }; | ||
|
|
||
| export const useClickGame = () => { | ||
| return useMutation({ | ||
| mutationFn: (clubName: string) => postGameClick(clubName), | ||
| }); | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,4 @@ | ||
| import { promotionHandlers } from './promotion'; | ||
|
|
||
| // 모든 MSW 핸들러를 여기에 통합 | ||
| export const handlers = [ | ||
| ...promotionHandlers, | ||
| // 다른 핸들러들을 여기에 추가 | ||
| ]; | ||
| export const handlers = [...promotionHandlers]; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| import styled from 'styled-components'; | ||
| import { media } from '@/styles/mediaQuery'; | ||
|
|
||
| export const PageContainer = styled.div` | ||
| position: relative; | ||
| overflow: hidden; | ||
| min-height: 100vh; | ||
| background: ${({ theme }) => theme.colors.gray[100]}; | ||
| display: flex; | ||
| flex-direction: column; | ||
| align-items: center; | ||
| padding: 48px 20px 80px; | ||
|
|
||
| ${media.mobile} { | ||
| padding: 32px 16px 60px; | ||
| } | ||
| `; | ||
|
|
||
| export const Blob = styled.div<{ | ||
| $size: number; | ||
| $top: string; | ||
| $left: string; | ||
| $color: string; | ||
| }>` | ||
| position: absolute; | ||
| width: ${({ $size }) => $size}px; | ||
| height: ${({ $size }) => $size}px; | ||
| top: ${({ $top }) => $top}; | ||
| left: ${({ $left }) => $left}; | ||
| background: ${({ $color }) => $color}; | ||
| border-radius: 50%; | ||
| filter: blur(60px); | ||
| pointer-events: none; | ||
| z-index: 0; | ||
| `; | ||
|
|
||
| export const Content = styled.div` | ||
| position: relative; | ||
| z-index: 1; | ||
| display: flex; | ||
| flex-direction: column; | ||
| align-items: center; | ||
| width: 100%; | ||
| max-width: 1400px; | ||
| `; | ||
|
|
||
| export const PageTitle = styled.h1` | ||
| font-size: 1.75rem; | ||
| font-weight: 800; | ||
| color: ${({ theme }) => theme.colors.gray[900]}; | ||
| margin-bottom: 4px; | ||
|
|
||
| ${media.mobile} { | ||
| font-size: 1.4rem; | ||
| } | ||
| `; | ||
|
|
||
| export const PageDescription = styled.p` | ||
| font-size: 0.95rem; | ||
| color: ${({ theme }) => theme.colors.gray[600]}; | ||
| margin-top: 4px; | ||
| `; | ||
|
|
||
| export const DesktopOnly = styled.div` | ||
| position: absolute; | ||
| right: 0; | ||
| top: 0; | ||
|
|
||
| ${media.tablet} { | ||
| display: none; | ||
| } | ||
| `; | ||
|
|
||
| export const MobileOnly = styled.div` | ||
| display: none; | ||
| width: 100%; | ||
| margin-top: 32px; | ||
|
|
||
| ${media.tablet} { | ||
| display: block; | ||
| } | ||
| `; | ||
|
|
||
| export const TopRow = styled.div` | ||
| position: relative; | ||
| display: flex; | ||
| justify-content: center; | ||
| width: 100%; | ||
| margin-bottom: 16px; | ||
|
|
||
| & > *:first-child { | ||
| text-align: center; | ||
| } | ||
|
|
||
| ${media.tablet} { | ||
| margin-bottom: 32px; | ||
| } | ||
| `; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.