티스토리 뷰

기본 컴포넌트 작성

title 컴포넌트

// Title.tsx

import styled from "styled-components";
import { ColorKey, HeadingSize } from "../../style/theme";

interface Props{
    children : React.ReactNode;
    size: "large"| "medium" | "small";
    color?: ColorKey;
}

function Title({children, size, color}: Props) {
    return( <TitleStyle size={size} color={color}>
        {children}
        </TitleStyle>
        );
}

const TitleStyle = styled.h1<Omit<Props, " children">>`
font-size: ${({theme, size}) => theme.heading[size].fontsize};
color: ${({theme, color}) => color ? theme.color
[color] : theme.color.primary};

`;

export default Title;

 

button 컴포넌트

//Button.tsx

import  styled  from "styled-components";
import { ButtonScheme, ButtonSize } from "../../style/theme";

interface Props{
    children : React.ReactNode;
    size: ButtonSize
    scheme: ButtonScheme
    disabled?: boolean;
    isLoading?: boolean;
}

function Button({children, size, scheme, disabled, 
    isLoading}: Props){
    return (
        <ButtonStyled size={size} scheme={scheme}
        disabled={disabled} isLoading={isLoading}>
            {children}
        </ButtonStyled>
    );
}

const ButtonStyled = styled.button<Omit<Props, "children">>`
font-size : ${({theme, size}) => theme.button[size].
    fontsize}; 
padding: ${({theme, size}) => theme.button[size].
    padding};
color : ${({theme, scheme}) => theme.buttonscheme[scheme].
    color};
background-color : ${({theme, scheme}) => theme.buttonscheme[scheme].
    backgroundcolor};      
border : 0;
border-radius:: ${({theme, scheme}) => theme.borderRadius.
    default}; 
opacity: ${({disabled}) => (disabled ? 0.5 : 1)}; 
pointer-events: ${({disabled}) => (disabled ? "none": "auto")};
cursor: ${({disabled}) => (disabled ? 'none' : 'pointer')}; 
`;

export default Button;

 

input 컴포넌트

import React, { ForwardedRef } from "react";
import styled from "styled-components";

interface Props extends React.InputHTMLAttributes<HTMLInputElement> {
    placeholder?: string;
    inputType?: "text" | "email" | "password" | "number";
}

const InputText = React.forwardRef(({placeholder, inputType, onChange, ...props} : Props, ref : ForwardedRef<HTMLInputElement>) => {
    return (
        <InputTextStyled placeholder={placeholder} ref={ref} type={inputType} onChange={onChange} {...props} />
    );
});

const InputTextStyled = styled.input`
    padding : 0.25rem 0.75rem;
    border : 1px solid ${({theme}) => theme.color.border};
    border-radius: ${({theme}) => theme.borderRadius.default};
    font-size: 1rem;
    line-height: 1.5;
    color : ${({theme}) => theme.color.text};
`;

export default InputText;

 

 

Header

(1) 로고 배치하기

assets폴더를 만들어 image폴더를 넣고 logo가 들어있는 이미지 파일을 넣는다.

import logo from "../../assets/images/logo.png"


function Header() {
  return (
    <HeaderStyle>
      <h1 className="logo">
        <img src={logo} alt="book store"/>
      </h1>
      <nav className="category"></nav>
    </HeaderStyle>
  );
}

(2) 카테고리 

// Header.tsx
import styled from "styled-components";
import ThemeSwicher from "../header/ThemeSwicher"; 
import logo from "../../assets/images/logo.png";

const CATEGORY = [
  {
    id: null,
    name: "전체"
  },
  {
    id: 0,
    name: "동화"  
  },
  {
    id: 1,
    name: "소설"  
  },
  {
    id: 2,
    name: "사회"
  },
];

function Header() {
  return (
    <HeaderStyle>
      <h1 className="logo">
        <img src={logo} alt="book store" />
      </h1>
      <nav className="category">
        <ul>
          {
            CATEGORY.map((item) => (
              <li key={item.id}>
                <a href={item.id===null?'/books' : `/books?category_id=${item.id}`}>
                {item.name}</a>
              </li>
            ))
          }
        </ul>
      </nav>
      <nav className="auth">
        <ul>
          <li>
            <a href="/login">
            로그인
            </a>
          </li> {/* ⛏️ 닫는 태그 위치 잘못되어 수정 */}
          <li>
            <a href="/login">
            회원가입
            </a>
          </li>
        </ul>
      </nav>
    </HeaderStyle>
  );
}

const HeaderStyle = styled.header`
  width: 100%;
  margin: 0 auto;
  max-width: ${({ theme }) => theme.layout.width.large};

  display: flex;
  justify-content: space-between; 
  align-items: center;
  padding:20px 0;
  border-bottom: 1px solid ${({theme}) => theme.color.background}; 

  .logo {
    img {
      width: 200px;
    }
  }
  .category {
    ul {
      display: flex;
      gap: 32px;
      li {
        a {
          font-size: 1.5rem;
          font-weight: 600;
          text-decoration: none;
          color: ${({theme}) => theme.color.text}; 

          &:hover {
            color: ${({theme}) => theme.color.primary}; 
          }
        }
      }
    }
  }
  .auth {
    ul {
      display: flex;
      gap: 32px;
      li {
        a {
          font-size: 1.5rem;
          font-weight: 600;
          text-decoration: none;
        }
      }
    }
  }  
`;

export default Header;

 

리액트 아이콘

https://react-icons.github.io/react-icons/

 

React Icons

 

react-icons.github.io

설치

npm install react-icons --save

 

Pooter

import  styled  from "styled-components";
import logo from '../../assets/images/logo.png';

function Footer() {
    return (
        <FooterStyle>
            <h1 className="logo">
                <img src={logo} alt="book store" />
            </h1>
            <div className="copyright">
                <p>
                    copyright(c), 2025, Book Store.
                </p>
            </div>
        </FooterStyle>
    )
}

const FooterStyle = styled.footer`
  width: 100%;
  margin: 0 auto;
  max-width: ${({ theme }) => theme.layout.width.large};
  border-top: 1px solid ${({theme}) => theme.color.background}; 
  padding :20px 0;
  display: flex;
  justify-content: space-between; 

.logo {
  img {
    width: 140px;
  }
}

.copyright {
  p {
    font-size: 0.75rem;
    color: ${({ theme }) => theme.color.text};
  }
}
`;


export default Footer;
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/12   »
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
글 보관함