npm i 

API 설치

 

npm run dev

 

파일내 설정된 포트번호 확인 

 

 

http://localhost:3000/api/docs/

 

 

 

애플리케이션에 설정할 데이터베이스 연결

 

 

MongoDB를 Node.js에연결하는 코드

 

각각의 에플리케이션 저장소를 가지고 게뱔

 

 

몽도DB의 클라우드 버전과 클라우드에서 순차적 세팅

몽도DB에서 제공하는 크라우드 서비스

https://www.mongodb.com/ko-kr/cloud

 

MongoDB Cloud

MongoDB Cloud는 최신 애플리케이션을 위한 통합 데이터 플랫폼으로, 글로벌 클라우드 데이터베이스, 검색, 데이터레이크, 모바일 및 애플리케이션 서비스를 포함하고 있습니다.

www.mongodb.com

signup 가입해주기

StartCluster Free 모드로 생성해주기

Node.js 서버연결을 위해 Security에서 네트워크 엑세스를 풀어줘야함

 

 

1. Network Access

통신이 될수있도록 네트워크 우회정보를 등록해준다.

 

 

2. Database Access

MongoDB 에 접속할수 있는 계정 생성

test / 1234 , read, wirte 기본설정값 확인후 Add User 클릭하여 user생성

 

 

드래그한 스트링값을 코드에 넣어주면 데이터베이스가 연결이 됨

스트링값을 덮어쓰고 <password> 를 설정해준 비밀번호 1234로 변경 해준다. 

Try It Out 을 클릭해주면 아래의 Input이 열리게 된다. 

 

vscode 터미널에서 정상적으로 뜨는 화먄

반응형

지난 글에서 NVM 설치내용을 다룸. 

 

NVM(Node Version Manager) 소개 및 설치

NVM 소개 및 설치 NVM(Node Version Manager) Node.js 의 버전을 관리하는 도구 프로젝트마다 사용되는 Node버전이 다를 경우 NVM을 통해 node 버전을 관리할 수 있다. 설치하기 1. Git Bash 터미널 환경에서 NV..

kang-ji.tistory.com

Node 버전변경 방법

프로젝트 경로의 터미널에서 nvm isntall [노드버전] 을 실행하면
해당버전이 설치돠면서 (최근)설치한 버전으로 세팅된다. 
버전 다운그레이드, 버전 업그레이드역시 install를 사용하여 변경해주면 됨. 

 

현재 Node 버전 12.18.0

 

추가로 필요한 Node 버전 install

nvm install 10.16.3

원래 버전으로 가고 싶을경우 다시 Install 하면 설치되며 사용 버전도 셋팅됨

nvm install 12.18.0

 

반응형

NVM 소개 및 설치

NVM(Node Version Manager) 

Node.js 의 버전을 관리하는 도구
Node 버전이 다를경우 충돌이 남.
프로젝트마다 사용되는 Node버전이 다를 경우 NVM을 통해 node 버전을 관리할 수 있다.

방법1. 설치하기 (- 이방법이 안될 경우 아래로 이동해서 방법 2로!!!! )

1. Git Bash 터미널 환경에서 NVM 공식 홈페이지에서 제공되는 명령을 실행하여 클론한다.

(윈도우의 경우 PowerShell 일 수 있는데 Bash로 변경해줘야함)

$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash

 

 

2. 설치가 완료되면 nvm -v 로 버전확인

$ nvm -v

 

3. 'nvm: command not found' 에러가 발생하게 되는데

명령어을 이용할때마다 NVM이 입력될 수 있게 세팅이 되지 않아 발생하는 에러.

 

4. 터미널 창에서 vi 편집기를 이용해서 home 디렉토리 밑에 있는 .bash_profile 또는 .bashrc 파일을 설정 해줘야한다.

vi ~/.bashrc 를 입력해주고 Enter. 
i 를 입력하여 삽입(Insert)쓰기모드로 전환한다.
$ vi ~/.bashrc

i
설정해줄 아래 구문을 복사하여 터미널창에 붙여준다. (이미 설정된 내용이 있을 경우 뒷쪽에 붙여준다. )
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm

 

5. ESC를 눌러서 쓰기모드를 해제.

 : wq 를 입력하여 편집된 파일을 저장해준다.

! 저장이 됬는지 확인하려면  vi ~/.bashrc 를 재실행하면 수정한파일 확인가능.
! 수정이력이 없을 때는 :q 를 입력하여 편집종료해준다.  (강제종료는 :q!)

 

6. 프로젝트 경로의 새터미널에서 nvm 또는  nvm -v 을 치면 성공적으로 실행되는 것을 볼 수 있음..!!!!!!!!!


 

본문자료 - NVM 깃헙 https://github.com/nvm-sh/nvm

 

GitHub - nvm-sh/nvm: Node Version Manager - POSIX-compliant bash script to manage multiple active node.js versions

Node Version Manager - POSIX-compliant bash script to manage multiple active node.js versions - GitHub - nvm-sh/nvm: Node Version Manager - POSIX-compliant bash script to manage multiple active nod...

github.com

 


방법2. 직접 설치하기

PC를 포맷해서 방법1. 대로 재설치를 해봤는데

갑자기 git관련 SSL 인증서 오류관련 메세지로 설치에 계속 오류가뜸... 

직접 설치 방법으로 간단하게 해결가능했다.

 

윈도우용 NVM 설치 URL

https://github.com/coreybutler/nvm-windows/releases

 

Releases · coreybutler/nvm-windows

A node.js version management utility for Windows. Ironically written in Go. - coreybutler/nvm-windows

github.com

이때 릴리즈 이슈 업데이트 시간때마다 node지원 버전대가 다르다. 

 

사용가능한 node 버전 조회하기

nvm list available

 

 

 

변경할 Node 버전 설치 

$nvm install [node버전]

nvm install 14.16.1

 

로컬에 설치된 node버전 조회

nvm list

 

변경할 node버전 사용하기

$nvm use [node버전]

nvm use 14.16.1

 

설정된 node버전 확인

node -v

 

https://devbirdfeet.tistory.com/101

 

Vue - (Windows) NVM 삭제하기

예전에 설치해놓은 Node.js를 깜박하고 NVM을 설치해 충돌이 났다. 급히 node.js를 지우고 nvm을 uninstall 하기위해 이것저것 뒤져보고 있었다. Vue - (Windows) NVM 삭제하기 stack overflow에서 여러 방법..

devbirdfeet.tistory.com

 

반응형

git clone

$ git clone https://github.com/joshua1988/vue-til-server.git

$cd vue-til-server

 

반응형

 

Vuter

 

Vue VSCode Snippets

 

ESLint

 

TSLint

 

반응형

https://swagger.io/

 

API Documentation & Design Tools for Teams | Swagger

 

swagger.io

 

반응형

Vue 3.X 이상의 경우 ES6사용으로 인해 IE브라우저를 지원하지 않는다 
IE 지원을 위해 polyfill등의 추가 세팅이 필요

Polyfill 

Vue 3.X 이상의 경우 ES6사용으로 인해 IE브라우저를 지원하지 않는다 
IE 지원을 위해 polyfill등의 추가 세팅이 필요
  • @babel/polyfill, @babel/preset-env 설치 
npm install --save @babel/polyfill
npm install --save-dev @babel/preset-env
  • main.js (※ 최상단에 위치할 것)
//main.js

import '@babel/polyfill'
import Vue from 'vue'

 

  • vue.config.js 세팅된 선언이 많을 경우 하단에 ' , ' 입력 후 이어서 붙여주기
//vue.config.js

const ansiRegex = require('ansi-regex');

module.exports = {
	transpileDependencies: [ansiRegex]
}

 

  • babel.config.js
// babel.config.js

module.exports = {
	presets: [
		['@babel/preset-env']
	]
}

 

반응형

vue.config.js

- vue.config.js 파일에 configureWebpack 옵션을 추가

- 프로젝트 bulid 시 css 와 js 파일 단일파일로 추출 (컴파일)

// vue.config.js
module.exports = {
  css: {
  	extract: {
    	filename: 'portfolio_ui' +"-"+ require("./package.json").version + '.min.css'
    },
  },
  configureWebpack: {
    output: {
        filename: 'portfolio_ui' +"-"+ require("./package.json").version + '.min.js'
    },
    optimization: {
        splitChunks: false
    }
  },
}
반응형

@mixin 

재사용할 스타일의 선언그룹을 만들면 불필요한 중복을 줄일 수 있다.

css에서 다양한 브라우저를 지원하기위해 vendor prefix를 여러차례 재사용할 경우가 있는데 이때 재사용할 CSS 선언그룹을 만들 수 있다. 

 

_mixins.scss

//----------------------------------
//      Vendor Prefix
//----------------------------------
// @param {*} $property Property
// @param {*} $value Value
@mixin prefix($property, $value) {
  -webkit-#{$property}: $value;
  -moz-#{$property}: $value;
  -ms-#{$property}: $value;
  -o-#{$property}: $value;
  #{$property}: $value;
}

// @param {Size} $radius [5px] - Radius
// @require {mixin} prefix

@mixin border-radius($radius: 5px) {
  @include prefix("border-radius", $radius);
}

//----------------------------------
//      Animation & keyframes
//----------------------------------
// Keyframes
// @param {*} $animation-name - Animation name
// @content [Animation css]

@mixin keyframes($animation-name) {
  @-webkit-keyframes #{$animation-name} {
    @content;
  }
  @-moz-keyframes #{$animation-name} {
    @content;
  }
  @-ms-keyframes #{$animation-name} {
    @content;
  }
  @-o-keyframes #{$animation-name} {
    @content;
  }
  @keyframes #{$animation-name} {
    @content;
  }
}

// Animation
// @param {*} $str - name duration timing-function delay iteration-count direction fill-mode play-state ([http://www.w3schools.com/cssref/css3_pr_animation.asp](http://www.w3schools.com/cssref/css3_pr_animation.asp))
// @require {mixin} css3-prefix

@mixin animation($str) {
  @include prefix("animation", $str);
}

//------------------
//   placeholder
//------------------

@mixin optional-at-root($sel) {
  @at-root #{if(not &, $sel, selector-append(&, $sel))} {
    @content;
  }
}

@mixin placeholder {
  @include optional-at-root("::-webkit-input-placeholder") {
    @content;
  }

  @include optional-at-root(":-moz-placeholder") {
    @content;
  }

  @include optional-at-root("::-moz-placeholder") {
    @content;
  }

  @include optional-at-root(":-ms-input-placeholder") {
    @content;
  }
}

//  float  clearfix
@mixin clearfix {
  &::before {
    content: "";
    display: block;
    clear: both;
    overflow: hidden;
   // visibility: hidden;
    height: 0;
  }
}

@mixin ghostVerticalAlign() {
  &:before {
    content: "";
    display: inline-block;
    vertical-align: middle;
    height: 100%;
    width: 0.1px;
  }
}

// generic transform
@mixin transform($transforms) {
  -moz-transform: $transforms;
  -o-transform: $transforms;
  -ms-transform: $transforms;
  -webkit-transform: $transforms;
  transform: $transforms;
}

// rotate
@mixin rotate($deg) {
  @include transform(rotate(#{$deg}deg));
}

// scale
@mixin scale($scale) {
  @include transform(scale($scale));
}
// translate
@mixin translate($x, $y) {
  @include transform(translate($x, $y));
}
@mixin translateX($x) {
  @include transform(translateX($x));
}
@mixin translateY($y) {
  @include transform(translateY($y));
}

//transform origin
@mixin transform-origin($origin) {
  moz-transform-origin: $origin;
  -o-transform-origin: $origin;
  -ms-transform-origin: $origin;
  -webkit-transform-origin: $origin;
  transform-origin: $origin;
}

// Flexbox display
@mixin flexbox {
  display: -webkit-box;
  //@debug: -webkit-flex;
  display: -moz-flex;
  display: -ms-flexbox;
  display: flex;
}

@mixin justify-content($justify) {
  -webkit-justify-content: $justify;
  -moz-justify-content: $justify;
  -ms-justify-content: $justify;
  justify-content: $justify;
  -ms-flex-pack: $justify;
}
@mixin align-items($align) {
  -webkit-algin-items: $align;
  //algin-items: $align;
}

//Get the value for justify-content
@function getJustify($arg) {
  $justify: (
    "sa": space-around,
    "sb": space-between,
    "se": space-evenly,
    "center": center,
    "fs": flex-start,
    "fe": flex-end,
  );

  @each $key, $value in $justify {
    @if ($key == $arg) {
      @return $value;
    }
  }
}

//Get the value for align-items
@function checkAlign($arg) {
  $align: (
    "b": baseline,
    "s": stretch,
    "sa": space-around,
    "sb": space-between,
    "center": center,
    "fs": flex-start,
    "fe": flex-end,
  );

  @each $key, $value in $align {
    @if ($key == $arg) {
      @return $value;
    }
  }
}

// Display flex
@mixin display-flex() {
  @include flexbox;
  @content;
}


@mixin hover-support {
  @media not all and (pointer: coarse) {
    &:hover {
      @content;
    }
  }
}

 

_common.scss

input { 
  @include prefix(box-sizing, border-box);
  @include prefix(appearance, none);
  @include placeholder {
    color: #aeaeae;
    opacity: 1;
  }
}
반응형

Variables (변수)

$를 사용하여 변수를 지정한다. 중복된 단어를 변수로 치환하여 유지보수가 쉬워진다.

 

_variables.scss


// font-family
$font-bk: "NotoBK", san-serif;
$font-b: "NotoB", san-serif;
$font-m: "NotoM", san-serif;
$font-r: "NotoR", san-serif;
$font-dl: "NotoDL", san-serif;
$font-l: "NotoL", san-serif;

// txt-colors
$txt-gray: #747473;
$txt-def: #333;
$txt-disabled: #b8b8b8;
$txt-pink: #f34176;
$txt-red: #ea6575;
$txt-navy: #24364f;
$txt-blue: #2b40ab;
$txt-yw: yellow;

 

_common.scss

- 등록한 변수 사용하기

body {
	font-family: $font-r;
    color: $txt-def;
}

 

반응형

Nesting (중첩)

계층적으로 상속되는 CSS를 더욱 계층적으로 보이게 만드는 기능으로 중괄호가 겹쳐져서 작성됩니다.

관련 요소들을 그룹화 하여 보다 깔끔해지고 중복을 최소화합니다.

// scss
nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }
  
  li {
  	display: block;
  }
  
  a {
    display: blick;
    padding: 6px 12px;
    text-decoration: none;
  }
}
반응형

CSS Pre-Processor란?

자신만의 특별한 구문(Syntax)을 가지고 CSS를 생성하는 프로그램이다.

CSS의 문제점을 프로그래밍 방식, 즉 변수·함수·상속 등 일반적인 프로그래밍 개념을 사용하여 보완한다.

CSS 전처리기에는 다양한 모듈이 존재하는데 그 중에서도 Sass·Less·Stylus가 가장 많이 사용된다.

CSS 전처리기는 공통 요소 또는 반복적인 항목을 변수 또는 함수로 대체할 수 있는 재사용성, 임의 함수 및 내장 함수로 인해 개발 시간과 비용 절약, 중첩·상속과 같은 요소로 인해 구조화된 코드 유지 및 관리 용이 등의 장점이 있다.

반면 전처리기를 위한 도구가 필요하고 다시 컴파일하는데 시간이 소요된다는 단점도 존재한다.

 

CSS Pre-Processor 사용률

 

SASS
- 가장 오래된 전처리기. 활발히 개발되고 있으며, 가장 많은 개발자들이 선택한 라이브러리
- Ruby, Node-sass 

Less
- 브라우저에 내장된 JS인터프리터만으로 컴파일 가능하므로 디펜던시에서 자유로움
- Node.js 기반으로 구동되며 Sass다음으로 활발히 개척되고 있어서, 유용한 라이브러리나 mixin 구현물들을 쉽게 찾을 수 있다.

PostCSS
- Sass, Less 와 같은 전처리기는 내부에서 제공하는 문법이 정해져있고 한정적이지만 PostCSS는 플러그인이 굉장히 다양하다. 이 때문에 최근 Sass와 Less보다 PostCSS사용에 대한 높은 만족도로 선호도가 올라감.

Stylus
- 상대적으로 프로그래밍 언어의 특징을 많이 포함하고 있습니다.
- CSS 프로퍼티 내에서 연산자나 함수, 루프 등을 비교적 자유롭게 사용할 수 있습니다.
- 반대로 위 특징때문에 문법에 혼재가 있어서 처음 전처리를 시작하는 사람에게는 상대적으로 장벽이 높습니다.

 

 

반응형

반응형 (PC,태블릿,모바일) 웹브라우저 환경에서 미지원화면 대체 컨텐츠 노출 대응

모바일 가로모드 미지원시 대체화면이 노출되도록 대응하는 내용입니다.

 

NotSupport.vue라는 미지원대체화면 컨텐츠 파일생성

 

App.vue

- 루트 파일인 App.vue에서 NotSupport 연결

<!-- App.vue -->
<template>
	<NotSupport v-show="isNotSupport" id="isNotSupport"/>
</template>
<script>
import Vue from 'vue'
import NotSupport from './components/NotSupport.vue';

export default {
  	name : 'App',
    data () {
      return {
        isNotSupport: false,
      }
    },
    components : { 
      NotSupport,
    },
 
}
</script>

- 디바이스 감지에 대한 스크립트 

<!-- App.vue -->
<script>
export default { 
    ...

    methods : {
      // 미지원 대체화면
      srceenHandler() {
        // 모바일 & 태블릿 구분
        var mobileTablet = /Android|Mobile|iP(hone|od|ad)|BlackBerry|IEMobile|Kindle|NetFront|Silk-Accelerated|(hpw|web)OS|Fennec|Minimo|Opera M(obi|ini)|Blazer|Dolfin|Dolphin|Skyfire|Zune/;

        // 세로모드 구분
        var isPortrait = window.innerWidth <= window.innerHeight;

        if (navigator.userAgent.match(mobileTablet)) {
          if (navigator.userAgent.match(/iPad|Android/i)) {
            // 아이패드, 안드로이드 OS
            if (window.matchMedia("(min-width: 361px) and (max-width: 600px)").matches) {
              if (isPortrait) {
                // 세로 모드일때 
                this.isNotSupport = false;
              } else {
                // 가로 모드일때
                this.isNotSupport = true;
              } 
            } else {
              this.isNotSupport = false;
            }

          } else if(navigator.userAgent.match(/iPhone|iPod/i)) {
            // 아이폰
            if (isPortrait) {
              // 세로 모드일때 
              this.isNotSupport = false;
            } else {
              // 가로 모드일때
              this.isNotSupport = true;
            } 
          } else {
            if (window.matchMedia("(max-width: 767px)").matches) {
              if (isPortrait) {
                // 세로 모드일때 
                this.isNotSupport = false;
              } else {
                // 가로 모드일때
                this.isNotSupport = true;
              } 
            } else {
              this.isNotSupport = false;
            }
          }
        } else { 
            // PC 
            if (window.matchMedia("(max-width: 767px)").matches) {
              if (window.innerWidth <= window.innerHeight) {
                // 세로 모드일때 
                this.isNotSupport = false;
              } else {
                // 가로 모드일때
                this.isNotSupport = true;
              } 
            } else {
              this.isNotSupport = false;
            }
        }
      },
  }
 
}
</script>

 

- 각 해당되는 라이프사이클에 screenHandler 이벤트 등록

// app.vue

export default {
  name : 'App',
  data () {
    return {
      isNotSupport: false,
    }
  },
  components : { 
  	NotSupport,
  },
  beforeCreate() {
    window.addEventListener('load', this.srceenHandler);
  },
  created: function() {
    window.addEventListener('load', this.srceenHandler);
    window.addEventListener('resize', this.srceenHandler);
  },
  mounted() {
    window.addEventListener('resize', this.srceenHandler);
	},
  beforeDestroy() {
    // 컴포넌트가 제거되기 직전 이벤트리스너 해제
    window.removeEventListener('resize', this.srceenHandler);
  },
 }

 

반응형

TortoiseGit

TortoiseGit은 깃 버전 관리 클라이언트의 하나로, 파일 탐색기로 구현되어 있고 TortoiseSVN에 기반을 둔다. GNU 일반 공중 사용 허가서로 출시되는 자유 소프트웨어

 

Tortoise Git을 사용하기 위해선 Git을 설치해야한다.

https://gitforwindows.org/

 

Git for Windows

Git for Windows focuses on offering a lightweight, native set of tools that bring the full feature set of the Git SCM to Windows while providing appropriate user interfaces for experienced Git users and novices alike. Git BASH Git for Windows provides a BA

gitforwindows.org

 

TortoiseGit 사이트에 접속한다.
자신의 Windows 환경에 맞게 32-bit 또는 64-bit을 선택하여 다운로드 받는다.
TortoiseGit 설치 파일과 언어팩은 함께 받는다.

 

Download – TortoiseGit – Windows Shell Interface to Git

Other resources Debug symbols, language dlls and other resources can be found on our dedicated download server: download.tortoisegit.org/tgit/2.12.0.0/. Preview releases The preview releases are built from the latest code that represents the cutting edge o

tortoisegit.org

 

반응형

특정 CSS문제가 생기지 않도록 하는 스니펫 콜렉션

이미지 늘려짐/찌그러짐 방지

object-fit: cover;

 

Flexbox 줄바꿈

flex-wrap: wrap;

 

고정 높이 -> height 보다는 min-height ,고정 너비 -> width  보다는 min-width 사용

min-width: 320px;
min-height: 980px;

 

CSS 변수 폴백 값 주기

max-width: calc(100% - var(--actions-width, 70px));

 

줄바꿈 되지 않아야할 긴 콘텐츠 

text-overflow: ellipsis; white-space:nowrap; overflow: hidden;

 

스크롤 연쇄 잠금

overscroll-behavior-y: contain;

 

배경 반복 제거

background-repeat: no-repeat;

 

필요할때만 스크롤바 보이기

overflow-y: auto;

 

스크롤바 생길때 레이아웃 변화 없애기

scrollbar-gutter: stable;

 

Flexbox 에서 최소 콘텐츠 사이즈 지정

min-width: 0; /*기본값이 auto 여서 overflow 발생*/

 

CSS Grid에서 최소 콘텐츠 사이즈 지정 minmax() 사용

Flexbox 아이템 배열시 justify-content: space-between; 대신 gap: 1rem; 사용

gap: 1rem;

 

이미지 최대 넓이 지정

max-width: 100%

 

이미지 위에 하얀 텍스트 올리때 이미지 로딩 실패시 대응

background-color: grey;


- 버티컬 미디어 쿼리 활용 → position:sticky 같은거 쓸 때 특정 세로크기 이상에서만 적용 @media (min-height:600px) {}
- CSS Grid 위에서 고정 값 사용은 조심 → 항상 미디어 쿼리 사용할 것
- CSS Grid 사용시 Auto Fit vs. Auto Fill → 대부분의 경우 auto-fill 이 나음
- 그리드 컨테이너 차일드에 postition: sticky 사용시 align-self: start 적용
- 그룹 셀렉터 지정은 다른 브라우저에서는 안될수 있으니 각각으로 분리할 것


https://developer.mozilla.org/ko/docs/Web/CSS/var() 

 

var() - CSS: Cascading Style Sheets | MDN

CSS var() 함수는 사용자 지정 속성 (en-US), 또는 "CSS 변수"의 값을 다른 속성의 값으로 지정할 때 사용합니다.

developer.mozilla.org

A Complete Guide to Flexbox

https://css-tricks.com/snippets/css/a-guide-to-flexbox/

 

A Complete Guide to Flexbox

Our comprehensive guide to CSS flexbox layout. This complete guide explains everything about flexbox, focusing on all the different possible properties for the parent element (the flex container) a…

css-tricks.com


Best CSS Code Snippet Sites

https://css-tricks.com/snippets/

 

Code Snippets

Visit the post for more.

css-tricks.com

https://snipplr.com/

 

Code Snippet - Snipplr Social Repository

 

snipplr.com

https://stackoverflow.com/questions/tagged/css

 

Newest 'css' Questions

Stack Overflow | The World’s Largest Online Community for Developers

stackoverflow.com



본문 참고 https://news.hada.io/topic?id=5512 

 

방어적(Defensive) CSS | GeekNews

특정 CSS문제가 생기지 않도록 하는 스니펫 콜렉션- Flexbox 줄바꿈 → flex-wrap: wrap;- 여유 공간 주기 → margin-right: 1rem;- 줄바꿈 되지 않아야할 긴 콘텐츠 → text-overflow: ellipsis; white-space:nowrap; overflow:

news.hada.io

 

반응형

+ Recent posts