Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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 src/frontend/src/components/MyRoomCard/index.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const Card = styled.div`
`;

export const Thumbnail = styled.div`
width: 124px;
width: 120px;
flex-shrink: 0;
aspect-ratio: 16 / 9;
border-radius: 0.625rem;
Expand Down
17 changes: 15 additions & 2 deletions src/frontend/src/components/MyRoomCard/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import UserIcon from '@/assets/img/UsersLine.svg';
import TrashcanIcon from '@/assets/img/Trashcan.svg';
import ShareIcon from '@/assets/img/ShareLink.svg';
Expand All @@ -17,12 +17,25 @@ import {
Title,
UserCount,
} from './index.css';
import { getYoutubeThumbnail } from '@/utils/youtubeUtils';

export const MyRoomCard = ({ room }: { room: MyRoomDto }) => {
const [isHovered, setIsHovered] = useState(false);
const [isClickDelete, setIsClickDelete] = useState(false);
const [thumbnail, setThumbnail] = useState<string>(DefaultThumbnail);
const navigate = useNavigate();

useEffect(() => {
if (!room.playlistUrl) return;

const fetchThumbnail = async () => {
const url = await getYoutubeThumbnail(room.playlistUrl ?? '', 'default');
setThumbnail(url ?? DefaultThumbnail);
};

fetchThumbnail();
}, [room.playlistUrl]);

const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
navigate(`/room?code=${room.code}`);
Expand Down Expand Up @@ -60,7 +73,7 @@ export const MyRoomCard = ({ room }: { room: MyRoomDto }) => {
onMouseLeave={() => setIsHovered(false)}
>
<Thumbnail>
<img src={room.playlistUrl ? room.playlistUrl : DefaultThumbnail} alt={room.title} />
<img src={thumbnail} alt={room.title} />
</Thumbnail>
<Info>
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const Container = styled.div<VideoItemContainerProps>`
border-radius: 5px;
background-color: ${({ $isPreview }) =>
$isPreview ? 'var(--palette-line-normal-normal)' : 'var(--palette-static-white)'};
border: 1px solid #ddd
border: 1px solid #ddd;
cursor: pointer;
position: relative;
transition: all 0.2s ease;
Expand All @@ -38,7 +38,7 @@ export const Container = styled.div<VideoItemContainerProps>`
transition: transform 0.2s ease;
}

&:hover .button-container {
&:hover .button-container {
opacity: ${({ $isDragging }) => ($isDragging ? 0 : 1)};
visibility: ${({ $isDragging }) => ($isDragging ? 'hidden' : 'visible')};
}
Expand Down
22 changes: 21 additions & 1 deletion src/frontend/src/components/VideoCard/index.css.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getYoutubeThumbnail } from '@/utils/youtubeUtils';
import { styled } from 'styled-components';

export const VideoCardContainer = styled.div`
Expand All @@ -14,7 +15,7 @@ export const VideoCardContainer = styled.div`
}
`;

export const Thumbnail = styled.div`
export const Thumbnail = styled.div<{ $playlistUrl: string | undefined }>`
width: 100%;
aspect-ratio: 16 / 9;
border-radius: 0.625rem;
Expand All @@ -25,6 +26,25 @@ export const Thumbnail = styled.div`
width: 100%;
height: 100%;
object-fit: cover;
content: url(${props => getYoutubeThumbnail(props.$playlistUrl, 'maxres')});
}

@media (max-width: 639px) {
& > img {
content: url(${props => getYoutubeThumbnail(props.$playlistUrl, 'sd')});
}
}

@media (max-width: 479px) {
& > img {
content: url(${props => getYoutubeThumbnail(props.$playlistUrl, 'hq')});
}
}

@media (max-width: 319px) {
& > img {
content: url(${props => getYoutubeThumbnail(props.$playlistUrl, 'mq')});
}
}
`;

Expand Down
19 changes: 17 additions & 2 deletions src/frontend/src/components/VideoCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,32 @@ import {
import { RoomDto } from '@/api/endpoints/room/room.interface';
import DefaultThumbnail from '@/assets/img/DefaultThumbnail.svg';
import DefaultProfile from '@/assets/img/DefaultProfile.svg';
import { getYoutubeThumbnail } from '@/utils/youtubeUtils';
import { useEffect, useState } from 'react';
interface IVideoCard {
video: RoomDto;
onClick?: () => void;
}

export const VideoCard = ({ video, onClick }: IVideoCard) => {
const [thumbnail, setThumbnail] = useState<string>(DefaultThumbnail);

useEffect(() => {
if (!video.playlistUrl) return;

const fetchThumbnail = async () => {
const url = await getYoutubeThumbnail(video.playlistUrl ?? '', 'hq');
setThumbnail(url ?? DefaultThumbnail);
};

fetchThumbnail();
}, [video.playlistUrl]);

return (
<VideoCardContainer onClick={onClick}>
<Thumbnail>
<Thumbnail $playlistUrl={video.playlistUrl}>
<UserCount>{video.userCount}명</UserCount>
<img src={video.playlistUrl ? video.playlistUrl : DefaultThumbnail} alt={video.title} />
<img src={thumbnail} alt={video.title} />
</Thumbnail>
<VideoInfo>
<Profile>
Expand Down
29 changes: 29 additions & 0 deletions src/frontend/src/utils/youtubeUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export const getYoutubeVideoInfo = async (videoId: string) => {
const response = await fetch(
`https://www.googleapis.com/youtube/v3/videos?part=snippet&id=${videoId}&key=${import.meta.env.VITE_YOUTUBE_API_KEY}`,
);
const data = await response.json();
return data;
};

// 유튜브 썸네일 이미지 가져오기
// maxres: 1280p, sd: 640p, hq: 480p, mq: 320p, default: 120p
export const getYoutubeThumbnail = (
url: string | undefined,
quality: 'default' | 'mq' | 'hq' | 'sd' | 'maxres',
): string | undefined => {
if (!url) return undefined;

const videoId = url.split('v=')[1];
if (!videoId) return url;

const qualityMap = {
maxres: 'maxresdefault',
sd: 'sddefault',
hq: 'hqdefault',
mq: 'mqdefault',
default: 'default',
};

return `https://img.youtube.com/vi/${videoId}/${qualityMap[quality]}.jpg`;
};
Loading