Recent Posts
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
관리 메뉴

개발자 박가나

[241106 TIL] 본캠프 26일차 ('포켓몬 도감 만들기' 프로젝트 1일차) 본문

내일배움캠프

[241106 TIL] 본캠프 26일차 ('포켓몬 도감 만들기' 프로젝트 1일차)

gnchoco97 2024. 11. 6. 20:01

  📌 오늘의 TIL
  • [포켓몬 도감] 프로젝트

 

 

 [포켓몬 도감] 프로젝트 

프로젝트 셋업

vite를 사용해서 프로젝트를 셋업해준다.

yarn create vite [폴더명] --template react

 

디자인 및 퍼블리싱

styled-components 라이브러리를 이용해서 스타일을 적용시켜 주었다.

 

  • 페이지
/* Home.jsx */

import { useNavigate } from 'react-router-dom';
import styled from 'styled-components';
import Button from '../components/Button';

const Wrap = styled.div`
    height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 20px;
`;

const Logo = styled.img`
    width: 90vw;
    max-width: 600px;
`;

export default function Home() {
    const navigate = useNavigate();

    return (
        <Wrap>
        	<Logo src="src/assets/logo.png" alt="logo" />
        	<Button background="red" label="포켓몬 도감 시작하기" handleClick={() => navigate('/dex')} />
        </Wrap>
    );
}
/* Dex.jsx */

import styled from 'styled-components';
import Dashboard from '../components/Dashboard';
import PokemonList from '../components/PokemonList';
import MOCK_DATA from '../Data';

const Wrap = styled.div`
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20px;
    margin: 20px;
`;

export default function Dex() {
    return (
        <Wrap>
            <Dashboard />
            <PokemonList data={MOCK_DATA} />
        </Wrap>
    );
}
/* Detail.jsx */

import { useNavigate } from 'react-router-dom';
import styled from 'styled-components';
import Button from '../components/Button';

const Wrap = styled.div`
    height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 30px;
`;

const Character = styled.img`
    width: 200px;
`;

const Name = styled.p`
    font-size: 24px;
    font-weight: 700;
    color: #ff0000;
`;

const Description = styled.p`
    font-size: 16px;
`;

export default function Detail() {
    const navigate = useNavigate();

    return (
        <Wrap>
            <Character src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/143.png" alt="character" />
            <Name>잠만보</Name>
            <Description>타입 : 노말</Description>
            <Description>노말 타입의 포켓몬으로, 큰 몸집과 느긋한 성격을 가집니다.</Description>
            <Button label="뒤로 가기" background="black" handleClick={() => navigate('/dex')} />
        </Wrap>
    );
}

 

  • 컴포넌트
/* Button.jsx */

import styled from 'styled-components';

const Container = styled.div`
    ${({ type, background }) => `
        background-color: ${background};
        border-radius: 4px;
        color: #ffffff;
        font-size: ${type === 'main' ? '16px' : '14px'};
        font-weight: ${type === 'main' ? '700' : '500'};
        padding: ${type === 'main' ? '10px 20px' : '5px 10px'};
        cursor: pointer;
    `}
`;

export default function Button({ type = 'main', background, label, handleClick }) {
    return (
        <Container type={type} background={background} onClick={handleClick}>
        	{label}
        </Container>
    );
}
/* Bashboard.jsx */

import styled from 'styled-components';
import PokemonBall from './PokemonBall';

const Container = styled.div`
    width: 100%;
    max-width: 1240px;
    background-color: #f0f0f0;
    border-radius: 10px;
    padding: 20px;
`;

const Title = styled.p`
    font-size: 24px;
    font-weight: 700;
    color: #ff0000;
    text-align: center;
    margin-bottom: 20px;
`;

const BallContainer = styled.div`
    display: flex;
    justify-content: space-around;
    gap: 10px;
    overflow: scroll;
`;

export default function Dashboard() {
    return (
        <Container>
            <Title>나만의 포켓몬</Title>
            <BallContainer>
                <PokemonBall />
                <PokemonBall />
                <PokemonBall />
                <PokemonBall />
                <PokemonBall />
                <PokemonBall />
            </BallContainer>
        </Container>
    );
}
/* PokemonBall.jsx */

import styled from 'styled-components';

const Container = styled.div`
    min-width: 120px;
    min-height: 120px;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: #ffffff;
    border: 2px dashed #cccccc;
    border-radius: 10px;
`;

const Ball = styled.img`
	width: 60px;
`;

export default function PokemonBall() {
    return (
        <Container>
        	<Ball src="/src/assets/pokeball.png" />
        </Container>
    );
}
/* PokemonCard.jsx */

import styled from 'styled-components';
import Button from './Button';
import { useNavigate } from 'react-router-dom';

const Container = styled.div`
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    background-color: #ffffff;
    border-radius: 10px;
    box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.1);
    transition: transform 0.2s, box-shadow 0.2s;
    padding: 10px;

    &:hover {
        transform: translateY(-5px);
        box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1);
    }
`;

const Character = styled.img`
	width: 100px;
`;

const Name = styled.p`
    font-size: 16px;
    font-weight: 700;
    color: #000000;
`;

const Description = styled.p`
    font-size: 14px;
    color: #666666;
`;

export default function PokemonCard({ data }) {
    const navigate = useNavigate();

    return (
        <Container onClick={() => navigate(`/detail/${data.id}`)}>
            <Character src={data.img_url} />
            <Name>{data.korean_name}</Name>
            <Description>No. {String(data.id).padStart(3, '0')}</Description>
            <Button type="sub" background="red" label="추가" handleClick={() => {}} />
        </Container>
    );
}
/* PokemonList.jsx */

import styled from 'styled-components';
import PokemonCard from './PokemonCard';

const Container = styled.div`
    width: 100%;
    max-width: 1240px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 20px;
    background-color: #f0f0f0;
    border-radius: 10px;
    padding: 20px;
`;

export default function PokemonList({ data }) {
    return (
        <Container>
            {data.map((pokemon) => {
            	return <PokemonCard key={pokemon.id} data={pokemon} />;
            })}
        </Container>
    );
}