본문 바로가기

Front-End/React

React #11 (CSS - user & card)

반응형

 

※ 이전 프로젝트 (ch03_4) 에서 계속 이어서 진행.

https://chiro-j.tistory.com/74

 

React #10 (CSS - flexbox layout)

※ 사전 작업더보기깃허브 레포로 가서 실습에 쓸 파일만 가져오기 (ch03 > ch03_3 폴더) https://github.com/yisj777s/doit-react-webapp-typescript/tree/main터미널에서 아래 코드를 쳐서 그 아래에 있는 캡처(package.j

chiro-j.tistory.com

 

 

 

User Container

사용자 데이터 만들기

touch src/data/User.ts

 

사용자 타입 정의 (+ 사용자 생성 메서드 정의)

src/data/User.ts

import * as C from './chance'
import * as I from './image'


export type IUser = {
  uuid: string;
  name: string;
  jobTitle: string;
  email: string;
  avatar: string;
}

// prettier-ignore
export const makeUser = (
  uuid: string, name: string, jobTitle: string, email: string, avatar: string
): IUser => ({uuid, name, jobTitle, email, avatar})

export const makeRandomUser = (): IUser =>
  makeUser(
    C.randomUUID(),
    C.randomName(),
    C.randomJobTitle(),
    C.randomEmail(),
    I.randomAvatar()
  )

 

 

 

위에서 정의한 사용자 데이터를 반영

src/data/index.ts 

 

User 컴포넌트 구현

src/pages/User.tsx

import type { FC } from 'react'
import type { DivProps } from '../components'
import * as D from '../data'
import { Div, Avatar } from '../components'


export type UserProps = DivProps & {
  user: D.IUser
}


const User: FC<UserProps> = ({user, ...props}) => {

  const {name, email, jobTitle, avatar} = user;
  
  return (
    <Div {...props}>

      <div className="flex p-2">
        <Avatar src={avatar} size="2rem" />
        <div className="ml-2">
          <p className="font-blod">{name}</p>
          <p className="text-gray-500 line-clamp-1">{jobTitle}</p>
          <p className="text-blue-500 underline">{email}</p>
        </div>
      </div>
      
    </Div>
  )
}

export default User;

 

 

위에서 만든 사용자 데이터와 사용자 컴포넌트를 이용하여 페이지에 구현하기

src/pages/UserContainer.tsx

import {Title} from '../components'
import * as D from '../data'
import User from './User'


export default function UserContainer() {
  
  const children = D.makeArray(10)
    .map(D.makeRandomUser)
    .map(user => (
      <User
        key={user.uuid}
        user={user}
        className="m-2 text-xs border-2 border-blue-300 rounded-lg"
        minWidth="15rem"
        width="15rem"
      />
    ))
    
  return (
    <section className="mt-4">
      <Title>UserContainer</Title>
      <div className="flex flex-wrap items-center justify-center p-4 mt-4">
        {children}
      </div>
    </section>
  )
}

 

(기본적으로 flex-box 모델로 되어 있어서, 마우스 휠로 확대/축소 함에 따라 다르게 보여진다.)

 

 

 

Card Container

더 나아가 위의 User Container 기반으로 그 위에 이미지를 얹어 Photo Card Container로 만들어보자

 

카드 데이터 만들기

touch src/data/Card.ts

 

카드 타입 정의 (+ 카드 만드는 메서드 정의)

src/data/Card.ts

import type {IUser} from './User'
import {makeRandomUser} from './User'
import * as C from './chance'
import * as I from './image'
import * as D from './date'


export type ICard = {
  uuid: string
  writer: IUser
  image: string
  title: string
  paragraphs: string
  dayMonthYearDate: string
  relativeDate: string | null
}


export const makeCard = (
  uuid: string,
  writer: IUser,
  image: string,
  title: string,
  paragraphs: string,
  dayMonthYearDate: string,
  relativeDate: string | null
): ICard => ({uuid, writer, image, title, paragraphs, dayMonthYearDate, relativeDate})


export const makeRandomCard = () => {

  const date = D.makeRandomPastDate()

  return makeCard(
    C.randomUUID(),
    makeRandomUser(),
    I.randomImage(800, 600),
    C.randomTitleText(),
    C.randomParagraphs(5),
    D.makeDayMonthYear(date),
    D.makeRelativeDate(date)
  )
}

 

위에서 정의한 데이터를 반영하기

src/data/index.ts

 

 

위에서 앞서 작업했으니 이제 페이지에 구현해보자

src/pages/Card.tsx

import type {FC} from 'react'
import type {DivProps} from '../components'
import {Div, Icon} from '../components'
import * as D from '../data'
import User from './User'


export type CardProps = DivProps & {
  card: D.ICard
}

const Card: FC<CardProps> = ({card, ...props}) => {
  console.log(card)

  const {writer, image, title, paragraphs, dayMonthYearDate, relativeDate} = card
  const icons = ['home', 'search', 'settings', 'favorite'].map(name => (
    <Icon key={name} name={name} className="mr-20 text-3xl" />
  ))


  return (
    <Div {...props}>
      <div className="flex flex-col">
        <Div src={image} className="h-60" />

        <Div className="p-4" minHeight="16rem" height="16rem" maxHeight="16rem">
          <p className="mt-2 text-3xl font-bold text-center">{title}</p>

          <Div className="flex justify-between">
            <User user={writer} className="mt-2" />
            <Div className="mt-2">
              <p className="text-gray-500">{relativeDate}</p>
              <p className="text-gray-500">{dayMonthYearDate}</p>
            </Div>
          </Div>

          <p className="mt-2 line-clamp-4">{paragraphs}</p>
          <Div className="flex flex-row items-center justify-between p-2 mt-2 text-red-500">
            {icons}
          </Div>

        </Div>
      </div>
    </Div>
  )
}


export default Card;

 

(이것도 마찬가지로 화면 해상도에 따라 달리 보여진다.)

 

 

 

반응형

'Front-End > React' 카테고리의 다른 글

React #12-2 (CSS - daisyUI: Input & Modal)  (1) 2025.07.14
React #12-1 (CSS - daisyUI: Button & Icon)  (0) 2025.07.14
React #10 (CSS - flexbox layout)  (0) 2025.07.14
React #9 (CSS - 박스모델)  (2) 2025.07.10
React #8 (CSS - TailwindCSS)  (0) 2025.07.10