components

김종민·2022년 7월 25일
0

apple-market

목록 보기
3/37


들어가기
apple-market의 여러page에서 사용되는 components들을
정리해 보자

총 8개의 component를 만듬.
보면서 tailwindcss에 대해서도 정리가 됨.

1. button.tsx

import { cls } from '../libs/utils' ///? : 에 따라서 다르게 적용될 css를 설정하기 위한 hook!!

interface ButtonProps {
  large?: boolean
  text: string
  [key: string]: any
}
///button component를 사용하기 위해 보내주어야 할 props. [key:string]: any를 유심히본다.

export default function Button({
  large = false,
  onClick, ///button이기 때문에 onClick도 받는다.
  text,
  ...rest ///ButtonProps 외에 받는것은 ...rest로 처리함.
}: ButtonProps) {
  return (
    <button
      {...rest} ///ButtonProps 외에 받는것은 {...rest}로 처리함.
      className={cls(
        'w-full bg-orange-400 hover:bg-orange-600 text-white px-4 border text-lg border-transparent rounded-md shadow-lg font-medium foucs:ring-offset-2 focus:ring-2 focus:ring-orange-500 focus:outline-none',
        large ? 'py-3 text-base' : 'py-2 text-sm'
      )}
    >
      {text}
    </button>
  )
}

2. floating-button.tsx

사진올리기, 아이템 올리기, 라이브방송올리기 등, 고정되어 있는 버튼만들기
위의 버튼은 submit

import Link from 'next/link'
import React from 'react'

interface FloatingButton {
  children: React.ReactNode ///floating Button에 들어갈 것을 children으로 받음.
  href: string ///클릭했을떄 이동 될, page를 입력.
}

export default function FloatingButton({ children, href }: FloatingButton) {
  return (
    <Link href={href}> ///Link는 import되어야함, a와 같이 쓰여야 함.
      <a className="fixed hover:bg-orange-600 border-o aspect-square border-transparent transition-colors cursor-pointer bottom-24 opacity-70 right-5 shadow-lg bg-orange-400 rounded-full w-14 flex items-center justify-center text-white">
        {children}
      </a>
    </Link>
  )
}

3. input.tsx

이메일, password등을 입력하는 칸.

  label: string
  name: string
  kind?: 'text' | 'phone' | 'price'
  [key: string]: any
}
///Props로 label, name, kind?, [key:string]:any 를 받는다.

export default function Input({
  label,
  name,
  kind = 'text', ///default값은 'text'로~
  ...rest ///Props외에것은 ...rest로~
}: InputProps) {
  return (
    <div>
      <label
        className="mb-1 block text-sm font-medium text-gray-700"
        htmlFor={name}
      >
        {label}
      </label> ///Props에서 받은 label과 name을 먼저 처리한다.
      
      {kind === 'text' ? (
        <div className="rounded-md relative flex items-center shadow-lg">
          <input
            id={name}
            {...rest}
            className="appearance-none w-full px-3 py-2 border border-gray-300 rounded-md shadow-lg placeholder-gray-400 focus:outline-none focus:ring-orange-500 focus:border-orange-500"
          />
        </div>
      ) : null} ///kindrk text일 경우 처리하는 로직, id={name}으로 한다!!
      
      {kind === 'price' ? (
        <div className="rounded-md relative flex items-center shadow-lg">
          <div className="absolute left-0 pointer-events-none pl-3 flex items-center justify-center">
            <span className="text-gray-500 absolute left-1 text-sm">$</span>
          </div>
          <input
            id={name}
            {...rest}
            className="appearance-none w-full px-3 py-2 border border-gray-300 rounded-md shadow-lg placeholder-gray-400 focus:outline-none focus:ring-orange-500 focus:border-orange-500"
          />
          <div className="absolute right-0 pointer-events-none pr-3 flex items-center">
            <span className="text-gray-500">KRW</span>
          </div>
        </div>
      ) : null}
      ///kind가 price일 경우 처리하는 방법, $나 KRW같은 absolute가 들어가는것을
      ///집중해서볼것!!
      
      {kind === 'phone' ? (
        <div className="flex rounded-md shadow-lg">
          <span className="flex items-center justify-center px-3 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text0gray-500 select-none text-sm">
            +82
          </span>
          <input
            id={name}
            {...rest}
            className="appearance-none w-full px-3 py-2 border border-gray-300 rounded-md shadow-lg placeholder-gray-400 focus:outline-none focus:ring-orange-500 focus:border-orange-500"
          />
        </div>
      ) : null}
      ///kind가 phone일 경우 로직. 역시 id={name}으로 받고, +82가 처리되는 부분도 잘 본다.
      
    </div>
  )
}

4. item.tsx

하나의 item이 layout되는것.
클릭시 localhost:3000/items/[id]로 page이동됨.
heroicons 사용떄문에 코드가 길어졌을뿐.

import Link from 'next/link' ///item을 클릭시 items/[id]로 보내줘야함.
import React from 'react'

interface ItemProps {
  title: string
  id: number
  price: number
  comments: number
  hearts: number
}
///하나의 item이 받는 props

export default function Item({
  title,
  id,
  price,
  comments,
  hearts,
}: ItemProps) {
  return (
    <Link href={`/items/${id}`}> ///아이템 클릭시 위의 주소로 이동함.
      <a className="flex px-4 py-3 cursor-pointer justify-between shadow-lg">
        <div className="flex space-x-4">
          <div className="w-20 h-20 bg-gray-400 rounded-md" />
          <div className="pt-2 flex flex-col">
            <h3 className="text-sm font-medium text-gray-900">{title}</h3>
            <span className="font-medium mt-1 text-gray-900">${price}</span>
          </div>
        </div>
        <div className="flex space-x-2 items-end justify-end">
          <div className='flex space-x-0.5 items-center text-sm text-gray-600'>
            <svg
              xmlns="http://www.w3.org/2000/svg"
              className="h-6 w-6"
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
              strokeWidth="2"
            >
              <path
                strokeLinecap="round"
                strokeLinejoin="round"
                d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
              />
            </svg>
            <span>{hearts}</span>
          </div>
          <div className='flex space-x-0.5 items-center text-sm text-gray-600'>
            <svg
              xmlns="http://www.w3.org/2000/svg"
              className="h-6 w-6"
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
              strokeWidth="2"
            >
              <path
                strokeLinecap="round"
                strokeLinejoin="round"
                d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"
              />
            </svg>
            <span>{comments}</span> ///댓글 개수임..
          </div>
        </div>
      </a>
    </Link>
  )
}

5. layout.tsx

위의 header부분과
밑의 nav부분등
모든 page에 적용되는 component

import Link from 'next/link'
import { useRouter } from 'next/router' ///goBack을 사용하기 위해서 import함.
import React from 'react'
import { cls } from '../libs/utils'

interface LayoutProps {
  title?: string
  canGoBack?: boolean
  hasTabBar?: boolean 
  children: React.ReactNode  ///children의 속성을 잘 봐 놓는다.
}

export default function Layout({
  title,
  canGoBack,
  hasTabBar,
  children,
}: LayoutProps) {
  const router = useRouter()
  const onClick = () => {
    router.back()
  } ///back 화살표 누르면  한단계 back시킴.
  return (
    <div>
      <div className="bg-white w-full h-12 max-w-xl justify-center text-xl px-10 font-medium fixed text-gray-800 border-b top-o flex items-center shadow-lg">
        {canGoBack ? (
          <button onClick={onClick} className="absolute left-4">
            <svg
              xmlns="http://www.w3.org/2000/svg"
              className="h-6 w-6"
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
              strokeWidth="2"
            >
              <path
                strokeLinecap="round"
                strokeLinejoin="round"
                d="M10 19l-7-7m0 0l7-7m-7 7h18"
              />
            </svg>
          </button>
        ) : null}
       ///canGoBack이 있을때, header 코딩!!! 
       
        {title ? (
          <span className={cls(canGoBack ? 'mx-auto' : '', '')}>{title}</span>
        ) : null}
        ////title이 있을때, header 부분.
        
      </div>
      ///header부분 끝
      
      <div className={cls('pt-16', hasTabBar ? 'pb-16' : '')}>{children}</div>
      ///가운데 children부분 받는다.
      
      {hasTabBar ? (
      ///아랫부분  Nav 부분, 클릭시 이동 가능하게 Link를 5개에 다 걸어줌.
      ///Link걸떄는, Link와 a 로~
      
        <nav className="bg-white w-full max-w-lg text-gray-800 border-t opacity-70 fixed bottom-0 px-10 pb-3 pt-3 flex justify-between items-center">
          <Link href="/">
            <a
              className={cls(
                'flex flex-col items-center space-y-2',
                router.pathname === '/'
                  ? 'text-orange-500'
                  : 'hover:text-orange-500 transition-colors'
              )}
            >
              <svg
                xmlns="http://www.w3.org/2000/svg"
                className="h-6 w-6"
                fill="none"
                viewBox="0 0 24 24"
                stroke="currentColor"
                strokeWidth="2"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"
                />
              </svg>
              <span></span>
            </a>
          </Link>
          <Link href="/community">
            <a
              className={cls(
                'flex flex-col items-center space-y-2',
                router.pathname === '/community'
                  ? 'text-orange-500'
                  : 'hover:text-orange-500 transition-colors'
              )}
            >
              <svg
                xmlns="http://www.w3.org/2000/svg"
                className="h-6 w-6"
                fill="none"
                viewBox="0 0 24 24"
                stroke="currentColor"
                strokeWidth="2"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z"
                />
              </svg>
              <span>동네생활</span>
            </a>
          </Link>
          <Link href="/chats">
            <a
              className={cls(
                'flex flex-col items-center space-y-2',
                router.pathname === '/chats'
                  ? 'text-orange-500'
                  : 'hover:text-orange-500 transition-colors'
              )}
            >
              <svg
                xmlns="http://www.w3.org/2000/svg"
                className="h-6 w-6"
                fill="none"
                viewBox="0 0 24 24"
                stroke="currentColor"
                strokeWidth="2"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
                />
              </svg>
              <span>채팅</span>
            </a>
          </Link>
          <Link href="/live">
            <a
              className={cls(
                'flex flex-col items-center space-y-2',
                router.pathname === '/live'
                  ? 'text-orange-600'
                  : 'hover:text-orange-500 transition-colors'
              )}
            >
              <svg
                xmlns="http://www.w3.org/2000/svg"
                className="h-6 w-6"
                fill="none"
                viewBox="0 0 24 24"
                stroke="currentColor"
                strokeWidth="2"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z"
                />
              </svg>
              <span>라이브</span>
            </a>
          </Link>
          <Link href="/profile">
            <a
              className={cls(
                'flex flex-col items-center space-y-2',
                router.pathname === '/profile'
                  ? 'text-orange-600'
                  : 'hover:text-orange-500 transition-colors'
              )}
            >
              <svg
                xmlns="http://www.w3.org/2000/svg"
                className="h-6 w-6"
                fill="none"
                viewBox="0 0 24 24"
                stroke="currentColor"
                strokeWidth="2"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
                />
              </svg>
              <span>나의 애플</span>
            </a>
          </Link>
        </nav>
      ) : null}
    </div>
  )
}

6. message.tsx

chating에서 메세지 하나하나 나타내지는 component
reverse되는 부분을 유심히 잘 봐 놓는다.

import { cls } from '../libs/utils'

interface MessageProps {
  message: string
  reversed?: boolean
  avatarUrl?: string
}

export default function Message({
  message,
  reversed,
  avatarUrl,
}: MessageProps) {
  return (
    <div
      className={cls(
        'flex items-start ',
        reversed ? 'flex-row-reverse space-x-2 space-x-reverse' : 'space-x-2'
      )}
    >
      <div className="w-8 h-8 rounded-full bg-slate-400" />
      <div className="w-1/2 text-sm text-gray-700 p-2 border border-gray-300 rounded-md">
        <p>{message}</p>
      </div>
    </div>
  )
}

7. textarea.tsx

동네질문 등, 글쓰기 하는 부분!!!
label, name, [key:string]:any 부분을 잘 봐놓을 것!!!!

interface TextAreaProps {
  label?: string
  name?: string
  [key: string]: any
}

export default function TextArea({ label, name, ...rest }: TextAreaProps) {
  return (
    <div>
      {label ? (
        <label
          htmlFor={name}
          className="mb-1 block text-sm font-medium text-gray-700"
        >
          {label}
        </label>
      ) : null}
      <textarea
        id={name}
        className="mt-3 shadow-lg w-full focus:ring-orange-500 rounded-md border-gray-300 focus:border-orange-500"
        rows={4}
        {...rest}
      />
    </div>
  )
}

label의 htmlFor={name}부분과 <textarea id={name} 부분을 잘 봐 놓는다~~ {...rest}부분도

profile
코딩하는초딩쌤

0개의 댓글