ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 리액트 기초이론 5 - 컴포넌트 스타일링 2 - SASS 해답
    프론트엔드/React 연습과제 해답 2022. 3. 2. 13:15
    728x90

     

    * 연습과제 1

    import React from 'react'
    import './Button.scss'
    
    function Button({ children, size, color, width, handleClick, disabled }){
        return <button 
                    className={`Button ${size} ${color} ${width}`} 
                    onClick={handleClick} disabled={disabled}
                >{children}</button>
    }
    
    export default Button;
    
    Button.defaultProps = {
        size: 'medium',
        color: 'tomato',
        disabled: false
    }
    @use "sass:list";
    
    $colors: blue, tomato, grey;
    $hover-colors: skyblue, lightsalmon, lightgray; 
    $sizes: large, medium, small;
    
    $default-height: 50px;
    $default-padding-left: 10px;
    $default-padding-right: 10px;
    $default-font-size: 1rem;
    
    @mixin setBtnSize($size, $h, $pl, $pr, $fs){
      .#{$size}{
        height: $h;
        padding-left: $pl;
        padding-right: $pr;
        font-size: $fs;
      }
    }
    
    .Button {
      all: unset;
      color: white;
      cursor: pointer;
      border-radius: 5px;
      font-weight: bold;
      margin-left: 10px;
      display: inline-flex;
      align-items: center;
      justify-content: center;
    
      &:hover{
        opacity: 0.7;
      }
    }
    /* 버튼의 크기 설정 */
    @include setBtnSize(list.nth($sizes, 1), $default-height + 20px , $default-padding-left + 5px, $default-padding-right + 5px, $default-font-size + 0.2rem);
    @include setBtnSize(list.nth($sizes, 2), $default-height , $default-padding-left, $default-padding-right, $default-font-size);
    @include setBtnSize(list.nth($sizes, 3), $default-height - 20px , $default-padding-left - 5px, $default-padding-right - 5px, $default-font-size - 0.2rem);
    
    /* 버튼의 배경색 설정 */
    @each $color in $colors{
      .#{$color}{
        background: $color;
    
        &:hover{
          background: list.nth($hover-colors, list.index($colors, $color));
        }
      }
    }
    
    /* 전체 너비를 차지하는 버튼 */
    .fullWidth{
      width: 100%;
      margin-left: 0px;
      margin-top: 10px;
      margin-bottom: 10px;
    }

     

    * 연습과제 2

    import React from 'react'
    import './Modal.scss'
    
    function Modal({ open, children }){
        return <div className={`Modal ${open? "open": "close"}`}>{children}</div>
    }
    
    export default Modal;
    
    Modal.defaultProps = {
        open: false
    }
    $modal-func: (
      open: block,
      close: none
    );
    
    $modal-style: (
      header: (
        font-size: 1.2rem,
        font-weight: bold
      ),
      body: (
        font-size: 0.9rem,
        margin: 20px
      ),
      'body input': (
        width: 60%,
        height: 30px,
        border: 1px solid lightgray,
        border-radius: 5px,
        margin-bottom: 10px
      ),
      footer: (
        display: flex,
        justify-content: flex-end,
        align-items: center
      )
    );
    
    .Modal {
      width: 500px;
      margin: 100px auto;
      border: 1px solid tan;
      padding: 10px;
      text-align: center;
    }
    
    // 모달창 열고 닫기
    @each $key, $value in $modal-func{
      .#{$key}{
        display: $value;
      }
    }
    // 모달창 스타일링
    @each $classname, $attributes in $modal-style{
      .#{$classname}{
        @if($classname != 'body input'){ padding: 5px; }
    
        @each $key, $value in $attributes{
          #{$key}: $value;
        }
      }
    }

     

    * 연습과제 3

    import './App.scss';
    import React, { Component } from 'react'
    
    class App extends Component{
      state = {
        isSorted: false,
        products: null,
        sortedProducts: null
      }
      componentDidMount(){
        const API_URL = 'http://makeup-api.herokuapp.com/api/v1/products.json?brand=maybelline' 
        // 서버에서 데이터 가져오기
        fetch(API_URL)
        .then((res) => {
            return res.json()
        })
        .then((products) => {
          const sortedProducts = [...products] //  원본복사 
          sortedProducts.sort( (p1, p2) => parseFloat(p1.price) - parseFloat(p2.price) ) 
          this.setState({products, sortedProducts})
        })
      }
      toggleState = () => {
        this.setState({ isSorted: !this.state.isSorted})
      }
      
      render(){
        const { isSorted, products, sortedProducts } = this.state
    
        const displayProducts = (product) => {
          const item = (
            <div key={product.id} className='product'>
              <div className='product-img'><img src={product.image_link} alt={product.name}/></div>
              <div className='product-name'>{product.name} (${product.price})</div>
              <div className='product-description'>{product.description}</div>
              <div className='product-type'>{product.product_type}</div>
            </div>
          )
          return item
        }
        
        return (
          <>
            <div className="header">
              <button className="sort-btns" onClick={this.toggleState}>Price</button><br/>
            </div>
            
            <div className='root'>
              {isSorted ? 
                  sortedProducts && sortedProducts.map(displayProducts) 
                : products && products.map(displayProducts)}
            </div>
          </>
        )
      }
    }
    
    export default App;
    $primary-bg-color: peru;
    $primary-color: white;
    
    @mixin setPosition($jc, $ai, $fw){
      display: flex;
      flex-wrap: $fw;
      justify-content: $jc;
      align-items: $ai;
    }
    @mixin setFont($size, $weight){
      font-size: $size;
      font-weight: $weight;
      text-align: center;
    }
    @mixin setSize($width, $height){
      @if($width) { width: $width; }
      @if($height) { height: $height; }
    }
    @mixin setColor($bgc, $c){
      @if($bgc) { background: $bgc; }
      @if($c) { color: $c; }
    }
    
    .header{
      @include setSize(100%, 70px);
      @include setPosition(flex-end, center, nowrap);
      @include setColor($primary-color, null);
    
      position: fixed;
      left: 0;
      top: 0;
      right: 0;
      box-shadow: 1px 1px 5px 5px darkgray;
      z-index: 1;
    
      .sort-btns{
        all: unset;
        @include setSize(100px, 50px);
        @include setFont(1rem, bold);
        @include setColor($primary-bg-color, $primary-color);
    
        border-radius: 10px;
        cursor: pointer;
        margin-right: 10px;
      
        &:hover{
          opacity: 0.8;
        }
      }
    }
    
    .root{
      @include setSize(60%, null);
      @include setPosition(center, center, wrap);
      margin: 100px auto;
    
      .product{
        @include setSize(null, 500px);
        @include setColor($primary-bg-color, $primary-color);
      
        flex: 200px;
        box-shadow: 1px 1px 5px 5px $primary-bg-color;
        margin: 10px;
        overflow: hidden;
    
        .product-img{
          @include setSize(100%, 180px);
          overflow: hidden;
    
          img{
            @include setSize(100%, 100%);
          }
        }
        .product-name{
          @include setFont(1.1rem, bold);
        }
        .product-description{
          @include setFont(0.9rem, 400);
          margin-top: 15px;
        }
      }
    }
    728x90
Designed by Tistory.