-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* design: 노래 리스트 Flex direction 수정 * refactor: 컴포넌트 재사용을 위한 파일명, 컴포넌트 명 변경 * refactor: MainPage의 좋아요순 노래 목록 SongItemList 컴포넌트로 분리 * refactor: 정책 변경으로 type 명 변경 각 카테고리의 모든 노래가 좋아요 순으로 정렬되므로 변경하였음. 범용적으로 사용할 수 있도록 popular prefix 제거 * refactor: 컴포넌트에서 remote 함수 분리 * feat: 장르 type 필드 추가 * refactor: 변경된 api 명세 반영 장르 쿼리파람 추가 * chore: 파일명, 상수명 단수 복수 오류 수정 * refactor: 썸네일 컴포넌트 사이즈 추가 및 radius 수정 * feat: 전체장르 추가 및 remote 함수 수정 * feat: 장르별 top10 fetch 기능 구현 * refactor: Songitem의 순위, 좋아요 수 삭제 정책 변경으로 인한 디자인 수정 * refactor: msw fixture 데이터 수정 앨범 커버 resize 옵션 수정 * style: 스타일린트 적용 * design: 케러셀 border radius 통일 * feat: useValidParams 커스텀 훅 추가 params의 undefined 검증 + 에러를 해결해주고 원하는 type이 추론되도록 하는 훅 * refactor: 변경된 api 정책 반영 api url 경로 수정 및 쿼리파람 추가 * fix: useExtraFetch type 에러로 제네릭 수정 2개이상의 인자를 허용하도록 수정 * refactor: 스와이프 페이지 route 경로에 genre path parameter 추가 * fix: 라우트 경로 오류 수정 * refactor: 메인 페이지 아이템 첫 로드시에도 랜더되지 않도록 분기 추가
- Loading branch information
1 parent
d78c279
commit dbd4c8b
Showing
17 changed files
with
289 additions
and
204 deletions.
There are no files selected for viewing
This file contains 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
80 changes: 0 additions & 80 deletions
80
frontend/src/features/songs/components/PopularSongItem.tsx
This file was deleted.
Oops, something went wrong.
8 changes: 4 additions & 4 deletions
8
...gs/components/PopularSongItem.stories.tsx → ...res/songs/components/SongItem.stories.tsx
This file contains 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 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,49 @@ | ||
import { styled } from 'styled-components'; | ||
import Spacing from '@/shared/components/Spacing'; | ||
import Thumbnail from './Thumbnail'; | ||
|
||
interface SongItemProps { | ||
rank: number; | ||
title: string; | ||
singer: string; | ||
albumCoverUrl: string; | ||
totalLikeCount: number; | ||
} | ||
|
||
const SongItem = ({ albumCoverUrl, title, singer }: SongItemProps) => { | ||
return ( | ||
<Flex> | ||
<Thumbnail size="xl" src={albumCoverUrl} alt={`${title}-${singer}`} /> | ||
<Spacing direction="vertical" size={4} /> | ||
<SongTitle>{title}</SongTitle> | ||
<Singer>{singer}</Singer> | ||
</Flex> | ||
); | ||
}; | ||
|
||
export default SongItem; | ||
|
||
const Flex = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
color: ${({ theme: { color } }) => color.white}; | ||
`; | ||
|
||
const SongTitle = styled.div` | ||
overflow: hidden; | ||
grid-area: title; | ||
font-size: 14px; | ||
font-weight: 700; | ||
text-overflow: ellipsis; | ||
white-space: nowrap; | ||
`; | ||
|
||
const Singer = styled.div` | ||
overflow: hidden; | ||
grid-area: singer; | ||
font-size: 12px; | ||
text-overflow: ellipsis; | ||
white-space: nowrap; | ||
`; |
This file contains 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,81 @@ | ||
import { Link } from 'react-router-dom'; | ||
import styled from 'styled-components'; | ||
import SongItem from '@/features/songs/components/SongItem'; | ||
import Spacing from '@/shared/components/Spacing'; | ||
import ROUTE_PATH from '@/shared/constants/path'; | ||
import useFetch from '@/shared/hooks/useFetch'; | ||
import GENRES from '../constants/genres'; | ||
import { getHighLikedSongs } from '../remotes/song'; | ||
import type { Genre, Song } from '../types/Song.type'; | ||
|
||
interface SongItemListProps { | ||
genre: Genre; | ||
} | ||
|
||
const SongItemList = ({ genre }: SongItemListProps) => { | ||
const { data: songs } = useFetch<Song[]>(() => getHighLikedSongs(genre)); | ||
|
||
if (songs === null || songs?.length === 0) return; | ||
|
||
return ( | ||
<> | ||
<Title>{`${GENRES[genre]} Top 10`}</Title> | ||
<Spacing direction="vertical" size={16} /> | ||
<SongList> | ||
{songs?.map(({ id, albumCoverUrl, title, singer, totalLikeCount }, i) => ( | ||
<Li key={id}> | ||
<StyledLink | ||
to={`${ROUTE_PATH.SONG_DETAILS}/${id}/${genre}`} | ||
aria-label={`${GENRES[genre]} 장르 ${i + 1}등 ${singer} ${title}`} | ||
> | ||
<SongItem | ||
rank={i + 1} | ||
albumCoverUrl={albumCoverUrl} | ||
title={title} | ||
singer={singer} | ||
totalLikeCount={totalLikeCount} | ||
/> | ||
</StyledLink> | ||
</Li> | ||
))} | ||
</SongList> | ||
<Spacing direction="vertical" size={30} /> | ||
</> | ||
); | ||
}; | ||
|
||
export default SongItemList; | ||
|
||
const SongList = styled.ol` | ||
scroll-snap-type: x mandatory; | ||
overflow-x: scroll; | ||
display: flex; | ||
flex-direction: row; | ||
gap: 12px; | ||
align-items: flex-start; | ||
width: 100%; | ||
`; | ||
|
||
const Li = styled.li` | ||
scroll-snap-align: center; | ||
scroll-snap-stop: normal; | ||
max-width: 130px; | ||
`; | ||
|
||
const StyledLink = styled(Link)` | ||
width: 100%; | ||
&:hover, | ||
&:focus { | ||
background-color: ${({ theme }) => theme.color.secondary}; | ||
} | ||
`; | ||
|
||
const Title = styled.h2` | ||
align-self: flex-start; | ||
font-size: 18px; | ||
font-weight: 700; | ||
color: white; | ||
`; |
This file contains 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 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,20 @@ | ||
const GENRES = { | ||
ALL: '전체', | ||
DANCE: '댄스', | ||
HIPHOP: '힙합', | ||
BALLAD: '발라드', | ||
POP: '팝', | ||
RHYTHM_AND_BLUES: 'R&B/Soul', | ||
INDIE: '인디', | ||
ROCK_METAL: '락/메탈', | ||
TROT: '트로트', | ||
FOLK_BLUES: '포크/블루스', | ||
JAZZ: '재즈', | ||
CLASSIC: '클래식', | ||
J_POP: 'J-POP', | ||
EDM: 'EDM', | ||
ETC: '기타', | ||
} as const; | ||
` `; | ||
|
||
export default GENRES; |
This file contains 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,6 +1,13 @@ | ||
import fetcher from '@/shared/remotes'; | ||
import type { Genre, Song } from '../types/Song.type'; | ||
import type { SongDetail } from '@/shared/types/song'; | ||
|
||
export const getSongDetail = async (songId: number): Promise<SongDetail> => { | ||
return await fetcher(`/songs/${songId}`, 'GET'); | ||
}; | ||
|
||
export const getHighLikedSongs = async (genre: Genre): Promise<Song[]> => { | ||
const query = genre === 'ALL' ? '' : `?genre=${genre}`; | ||
|
||
return await fetcher(`/songs/high-liked${query}`, 'GET'); | ||
}; |
This file contains 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,14 +1,27 @@ | ||
import fetcher from '@/shared/remotes'; | ||
import type { Genre } from '../types/Song.type'; | ||
import type { SongDetail, SongDetailEntries } from '@/shared/types/song'; | ||
|
||
export const getSongDetailEntries = async (songId: number): Promise<SongDetailEntries> => { | ||
return await fetcher(`/songs/${songId}`, 'GET'); | ||
export const getSongDetailEntries = async ( | ||
songId: number, | ||
genre: Genre | ||
): Promise<SongDetailEntries> => { | ||
const query = genre === 'ALL' ? '' : `?genre=${genre}`; | ||
return await fetcher(`/songs/high-liked/${songId}${query}`, 'GET'); | ||
}; | ||
|
||
export const getExtraPrevSongDetails = async (songId: number): Promise<SongDetail[]> => { | ||
return await fetcher(`/songs/${songId}/prev`, 'GET'); | ||
export const getExtraPrevSongDetails = async ( | ||
songId: number, | ||
genre: Genre | ||
): Promise<SongDetail[]> => { | ||
const query = genre === 'ALL' ? '' : `?genre=${genre}`; | ||
return await fetcher(`/songs/high-liked/${songId}/prev${query}`, 'GET'); | ||
}; | ||
|
||
export const getExtraNextSongDetails = async (songId: number): Promise<SongDetail[]> => { | ||
return await fetcher(`/songs/${songId}/next`, 'GET'); | ||
export const getExtraNextSongDetails = async ( | ||
songId: number, | ||
genre: Genre | ||
): Promise<SongDetail[]> => { | ||
const query = genre === 'ALL' ? '' : `?genre=${genre}`; | ||
return await fetcher(`/songs/high-liked/${songId}/next${query}`, 'GET'); | ||
}; |
Oops, something went wrong.