Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
46 changes: 0 additions & 46 deletions src/entities/character/config/character.ts

This file was deleted.

6 changes: 1 addition & 5 deletions src/entities/character/model/character.type.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { CHARACTER_DATA } from '@/entities/character/config/character';

// 새 캐릭터 추가 시 CHARACTER_DATA에만 추가하면 타입이 자동으로 확장됨
export type CharacterType = keyof typeof CHARACTER_DATA;
export type StarCount = 1 | 2 | 3;

export interface CharacterData {
name: CharacterType;
name: string;
rarity: StarCount;
imageUrl: string;
imageBigUrl: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ export const CharacterImageContainer = styled.div`
height: 11.25rem;
`;

export const CharacterImage = styled.img`
max-width: 100%;
max-height: 100%;
object-fit: contain;
`;

export const DescriptionContainer = styled.div`
display: flex;
flex-direction: column;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useNavigate, generatePath, useLoaderData } from 'react-router';
import { BottomSheet, ActionArea } from '@/shared/design-system/ui';
import { CHARACTER_DATA } from '@/entities/character/config/character';
import { ROUTE } from '@/shared/config/route';
import useGetCharacter from '@/features/character-management/api/useGetCharacter';
import * as S from './index.styles';
Expand Down Expand Up @@ -30,13 +29,7 @@ function CharacterBottomSheet({ open, setOpen }: CharacterBottomSheetProps) {
>
<S.BottomSheetContainer>
<S.CharacterImageContainer>
<img
src={data.imageUrl}
alt={data.name}
style={{
...CHARACTER_DATA[data.name].imageSize.small,
}}
/>
<S.CharacterImage src={data.imageBigUrl} alt={data.name} />
</S.CharacterImageContainer>
<S.DescriptionContainer>
<S.CharacterTitle>두둥, {data.name} 등장!</S.CharacterTitle>
Expand Down
4 changes: 2 additions & 2 deletions src/features/character-management/ui/CharacterItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ interface CharacterCardProps {
}

function CharacterCard({ character }: CharacterCardProps) {
const { imageUrl, name, acquiredAt } = character;
const { imageBigUrl, name, acquiredAt } = character;

return (
<S.CardContainer>
<S.CharacterImage src={imageUrl} alt={name} />
<S.CharacterImage src={imageBigUrl} alt={name} />
<S.CharacterName>{name}</S.CharacterName>
<S.CharacterAcquiredDate>
{acquiredAt ? format(acquiredAt, 'yyyy.MM.dd') : null}
Expand Down
38 changes: 5 additions & 33 deletions src/pages/characterShare/CharacterSharePage.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,10 @@ export const CharacterCardContainer = styled.div`
display: flex;
width: 100%;
justify-content: center;
padding: ${getToken('padding.3')};
padding: 0.5rem 2.5rem;
background-color: ${getToken('bg.neutral')};
`;

export const CharacterCard = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
width: 19.375rem;
height: 25rem;
flex-shrink: 0;
border-radius: ${getToken('radius.xl')};
border: 1px solid ${getToken('border.normal')};
background-color: ${getToken('bg.normal')};
`;

export const EmptyStateTitle = styled.h1`
${applyTypography('typography.heading.medium')};
margin: 0;
Expand All @@ -56,27 +42,13 @@ export const PageTitle = styled.h1`
margin: 0;
`;

export const CharacterName = styled.span`
${applyTypography('typography.heading.small')};
color: ${getToken('fg.normal')};
`;

export const CharacterDescription = styled.span`
${applyTypography('typography.body.medium')};
color: ${getToken('fg.alternative')};
`;

export const DownloadButton = styled(TextButton)`
margin-top: 0.75rem;
margin-bottom: 1.25rem;
`;

export const CharacterImageContainer = styled.div`
display: flex;
width: 15rem;
height: 14.25rem;
justify-content: center;
align-items: center;
flex-shrink: 0;
margin-top: 1.5rem;
export const CharacterImage = styled.img`
width: 100%;
max-width: 19.375rem;
height: auto;
`;
56 changes: 15 additions & 41 deletions src/pages/characterShare/CharacterSharePage.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,31 @@
import { useRef } from 'react';
import { toPng } from 'html-to-image';
import saveAs from 'file-saver';
import { ActionArea, Header, showToast } from '@/shared/design-system/ui';
import { useLoaderData, useNavigate } from 'react-router';
import { ArrowLeft, Download } from '@/shared/assets/svgs/icon';
import { getToken } from '@/shared/design-system';
import { PageLayout } from '@/shared/ui/PageLayout';
import { CHARACTER_DATA } from '@/entities/character/config/character';
import { StarChip } from '@/features/character-management/ui';
import useGetCharacter from '@/features/character-management/api/useGetCharacter';
import * as S from './CharacterSharePage.styles';

const sanitizeFilename = (name: string): string => {
return name.replace(/[/\\:*?"<>|]/g, '_');
};

function CharacterSharePage() {
const { groupToken } = useLoaderData();
const { data, isLoading, isError } = useGetCharacter(groupToken);
const navigate = useNavigate();
const imageRef = useRef<HTMLDivElement>(null);

const handleDownload = () => {
const handleDownload = async () => {
if (!data) return;
// 돔 요소를 이미지로 변환
if (imageRef.current) {
// 390x390 사이즈로 이미지 다운로드
toPng(imageRef.current, { width: 390, height: 390 })
.then((dataUrl) => {
// 이미지 다운로드
saveAs(dataUrl, `${data.name}.png`);
showToast({
type: 'success',
content: '이미지 저장 완료!',
});
})
.catch(() => {
showToast({
type: 'error',
content: '이미지 저장 실패!',
});
});
try {
const response = await fetch(data.imageUrl);
if (!response.ok) throw new Error();
const blob = await response.blob();
saveAs(blob, `${sanitizeFilename(data.name)}.png`);
showToast({ type: 'success', content: '이미지 저장 완료!' });
} catch {
showToast({ type: 'error', content: '이미지 저장 실패!' });
}
};

Expand Down Expand Up @@ -93,23 +82,8 @@ function CharacterSharePage() {
<S.TitleContainer>
<S.PageTitle>캐릭터를 획득했어요!</S.PageTitle>
</S.TitleContainer>
<S.CharacterCardContainer ref={imageRef}>
<S.CharacterCard>
<StarChip count={data.rarity} />
<S.CharacterImageContainer>
<img
src={data.imageBigUrl}
alt={data.name}
style={{
...CHARACTER_DATA[data.name].imageSize.big,
}}
/>
</S.CharacterImageContainer>
<S.CharacterName>{data.name}</S.CharacterName>
<S.CharacterDescription>
{CHARACTER_DATA[data.name].description}
</S.CharacterDescription>
</S.CharacterCard>
<S.CharacterCardContainer>
<S.CharacterImage src={data.imageUrl} alt={data.name} />
</S.CharacterCardContainer>
<S.DownloadButton onClick={handleDownload}>
<Download width="1.25rem" color={getToken('fill.inverse.neutral')} />
Expand Down
Loading