궁금한 내용을 검색해보세요!
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
서근 개발노트
티스토리에 팔로잉
FRONT-END/CSS

(티스토리) 코드블럭에 클립보드로 복사 버튼 추가

서근
QUOTE THE DAY

-
Written by SeogunSEOGUN

반응형

이번에는 블로그에 코드블럭을 넣으면서 복사버튼이 코드블럭안에 나타나 버튼을 클릭시 클립보드로 복사가 되는 스크립트를 구현하고 티스토리에 적용 시켜볼까 합니다.

 

만약 티스토리 스킨편집에 대한 기초 지식이 없으시다면 아래 글을 먼저 읽고 와주세요!

 

(티스토리) 스킨 편집 기초 상식

안녕하세요. 제 블로그에는 티스토리에서 스킨을 적용하기 위해 다양한 포스팅이 존재합니다. 이번에는 티스토리에서 어떻게 스킨을 어떻게 편집하는지 아주 간단하게 알아보려고 합니다. 스

seons-dev.tistory.com

클립보드 복사 버튼 만들기

티스토리를 이용하는 많은 분들이 콘텐츠를 무단으로 복사할 수 없도록 플러그인을 사용하여 마우스 사용을 막아놓았습니다. 

 

하지만 코드를 자주 사용하는 블로그인 경우 아주 난감합니다...! 그렇기에 Copy & Paste 버튼이 거의 필수적으로 필요하죠. 코드 블록의 오른쪽 상단에 복사 버튼을 추가해서 사용자가 직접 드래그 복사하지 않고 편리하게 이용할 수 있도록 설정해 보도록 하겠습니다.

 

일단 코드 부분에 마우스를 가져가면 오른쪽에 버튼이 생기고 그 버튼을 누르면 코드의 내용이 클립보드로 복사됩니다.

JavaScript 코드 작성

우선적으로 해야 할 것은 clipboard.jsHTML에 넣어줘야 합니다.

(clipboard.js 사용법을 알고 싶으시다면 여기를 눌러주세요.)

    <!--코드블럭 복사 버튼1 -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<html>
  <header>
  
    <!--여기에 추가-->
  
    </header>
 
   <body>
     ...
        </body>
 </html>

복사 버튼 생성

이렇게 HTML clipboard.js를 불러왔습니다. 이게 버튼을 추가해주겠습니다. 아래 파일을 다운로드하여 업로드해주세요.

CodeBlockCopy.js
0.00MB

그리고 다음과 같이 코드를 추가해줍니다.

<!--코드블럭 복사 버튼2-->
<script src="./images/CodeBlockCopy.js"></script>
<html>
  <header>
      ...
    </header>
 
   <body>
   
    <!--여기에 추가-->
    
        </body>
 </html>

CodeBlockCopy 상세 코드 

// codeCopyButton.js
let pre = document.querySelectorAll('pre');

pre.forEach((snippet) => {
  let button = document.createElement('button');
  button.className = 'copy-btn';
  // button.innerText = 'Copy'; // Text 버튼을 이미지로 변경

  // (option) 마우스를 Code 블록에 올리면 버튼이 나타나도록 함
  button.addEventListener('mouseleave', clearTooltip);
  button.addEventListener('blur', clearTooltip);

  // (option) Text 버튼 -> 이미지 버튼
  let img = document.createElement('img');
  img.className = "clippy";
  img.setAttribute('width', '15');
  img.setAttribute('src', 'https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbocTTu%2FbtrrQrXMCOg%2FaMErQkgcDCRJJHHIg4O4Wk%2Fimg.png');
  img.setAttribute('alt', 'Copy to clipboard');
  button.appendChild(img);

  snippet.appendChild(button)
});

let copyCode = new ClipboardJS('.copy-btn', {
    target: function(trigger) {
      return trigger.previousElementSibling;
    }
});

copyCode.on('success', function(event) {
    event.clearSelection();
    showTooltip(event.trigger, '복사완료');
});

copyCode.on('error', function(event) {
    showTooltip(event.trigger, fallbackMessage(event.action));
});


function clearTooltip(event) {
    event.currentTarget.setAttribute('class', 'copy-btn');
    event.currentTarget.removeAttribute('aria-label');
}

function showTooltip(elem, msg) {
    elem.setAttribute('class', 'copy-btn tooltipped tooltipped-s');
    elem.setAttribute('aria-label', msg);
}

function fallbackMessage(action) {
    let actionMsg = '';
    let actionKey = (action === 'cut' ? 'X' : 'C');
    if (/iPhone|iPad/i.test(navigator.userAgent)) {
        actionMsg = 'No support :(';
    } else if (/Mac/i.test(navigator.userAgent)) {
        actionMsg = 'Press ⌘-' + actionKey + ' to ' + action;
    } else {
        actionMsg = 'Press Ctrl-' + actionKey + ' to ' + action;
    }
    return actionMsg;
}

CSS 스타일 적용

이렇게 성공적으로 버튼까지 생성을 했습니다. 이제 CSS 코드를 추가하여 사용자 스타일을 만들어주겠습니다. 아래 코드를 전체 복사하고 CSS파일에 붙여 넣어줍니다.

/* 코드블럭 복사버튼 스타일 */
pre {
    position: relative;
    overflow: visible;
    display: block;
    font-family: monospace;
    line-height: normal;
    padding-left: 0px;
    padding-right: 0px;
    white-space: nowrap;
    margin-top: 0px;
    margin-bottom: 20px;

}

pre code {
    line-height: 23px;
    margin: 0;
    font-size: 0.6em;
    letter-spacing: -0.6pt;
    font-family: "menlo";
    border-radius: 0px;
}

@media (min-width:992px) {
    pre code {
        font-size: 0.9em;
    }
}

/*코드블럭 버튼 애니메이션*/
@keyframes copy-btn-ani {
    25% {
        transform: rotate(0deg) scale(1.05);
    }

    50% {
        transform: rotate(0deg) scale(1);
    }

    75% {
        transform: rotate(0deg) scale(1.05);
    }
}

.dark-mode pre .copy-btn {
     background: #1a1a1a9c;
}
pre .copy-btn {
    -webkit-transition: opacity .3s ease-in-out;
    -o-transition: opacity .3s ease-in-out;
    transition: opacity .3s ease-in-out;
    opacity: 0;
    position: absolute;
    background: #5757579c;
    border: 1px solid #575757;
    border-radius: 20px;
    right: 18px;
    top: 17px;
}

.copy-btn:hover {
    animation: copy-btn-ani 0.8s linear 1;
}

pre:hover .copy-btn,
pre .copy-btn:focus {
    opacity: 1;
}

.clippy {
    margin: 5px 5px 1px 5px;
    position: relative;
    top: 0px;
    filter: invert();
}

.copy-btn[disabled] .clippy {
    opacity: .3
}

code[class*="language-"],
pre[class*="language-"] {
    color: black;
    background: none;
    text-shadow: 0 1px white;
    font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
    text-align: left;
    white-space: pre;
    word-spacing: normal;
    word-break: normal;
    word-wrap: normal;
    line-height: 1.5;
    -moz-tab-size: 4;
    -o-tab-size: 4;
    tab-size: 5;
}

pre[class*="language-"]::-moz-selection,
pre[class*="language-"]::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"]::-moz-selection {
    text-shadow: none;
    background: #b3d4fc;
}

pre[class*="language-"]::selection,
pre[class*="language-"]::selection,
code[class*="language-"]::selection,
code[class*="language-"]::selection {
    text-shadow: none;
    background: #b3d4fc;
}

@media print {

    code[class*="language-"],
    pre[class*="language-"] {
        text-shadow: none;
    }
}

/*코드블럭 복사버튼 클릭시 텍스트*/
.tooltipped {
    position: relative
}

.tooltipped:after {
    position: absolute;
    z-index: 1000000;
    display: none;
    padding: 5px 8px;
    font: normal normal 11px/1.5 Helvetica, arial, nimbussansl, liberationsans, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
    color: #fff;
    text-align: center;
    text-decoration: none;
    text-shadow: none;
    text-transform: none;
    letter-spacing: normal;
    word-wrap: break-word;
    white-space: pre;
    pointer-events: none;
    content: attr(aria-label);
    background: rgb(142 89 55 / 80%);
    border-radius: 3px;
    -webkit-font-smoothing: subpixel-antialiased
}

.tooltipped:before {
    position: absolute;
    z-index: 1000001;
    display: none;
    width: 0;
    height: 0;
    color: rgba(0, 0, 0, .8);
    pointer-events: none;
    content: "";
    border: 5px solid transparent
}

.tooltipped:hover:before,
.tooltipped:hover:after,
.tooltipped:active:before,
.tooltipped:active:after,
.tooltipped:focus:before,
.tooltipped:focus:after {
    display: inline-block;
    text-decoration: none
}

.tooltipped-multiline:hover:after,
.tooltipped-multiline:active:after,
.tooltipped-multiline:focus:after {
    display: table-cell
}

.tooltipped-s:after,
.tooltipped-se:after,
.tooltipped-sw:after {
    top: 100%;
    right: 50%;
    margin-top: 5px
}

.tooltipped-s:before,
.tooltipped-se:before,
.tooltipped-sw:before {
    top: auto;
    right: 50%;
    bottom: -5px;
    margin-right: -5px;
    border-bottom-color: rgb(142 89 55 / 80%);
}

.tooltipped-se:after {
    right: auto;
    left: 50%;
    margin-left: -15px
}

.tooltipped-sw:after {
    margin-right: -15px
}

.tooltipped-n:after,
.tooltipped-ne:after,
.tooltipped-nw:after {
    right: 50%;
    bottom: 100%;
    margin-bottom: 5px
}

.tooltipped-n:before,
.tooltipped-ne:before,
.tooltipped-nw:before {
    top: -5px;
    right: 50%;
    bottom: auto;
    margin-right: -5px;
    border-top-color: rgba(0, 0, 0, .8)
}

.tooltipped-ne:after {
    right: auto;
    left: 50%;
    margin-left: -15px
}

.tooltipped-nw:after {
    margin-right: -15px
}

.tooltipped-s:after,
.tooltipped-n:after {
    -webkit-transform: translateX(50%);
    -ms-transform: translateX(50%);
    transform: translateX(50%)
}

.tooltipped-w:after {
    right: 100%;
    bottom: 50%;
    margin-right: 5px;
    -webkit-transform: translateY(50%);
    -ms-transform: translateY(50%);
    transform: translateY(50%)
}

.tooltipped-w:before {
    top: 50%;
    bottom: 50%;
    left: -5px;
    margin-top: -5px;
    border-left-color: rgba(0, 0, 0, .8)
}

.tooltipped-e:after {
    bottom: 50%;
    left: 100%;
    margin-left: 5px;
    -webkit-transform: translateY(50%);
    -ms-transform: translateY(50%);
    transform: translateY(50%)
}

.tooltipped-e:before {
    top: 50%;
    right: -5px;
    bottom: 50%;
    margin-top: -5px;
    border-right-color: rgba(0, 0, 0, .8)
}

.tooltipped-multiline:after {
    width: -webkit-max-content;
    width: -moz-max-content;
    width: max-content;
    max-width: 250px;
    word-break: break-word;
    word-wrap: normal;
    white-space: pre-line;
    border-collapse: separate
}

.tooltipped-multiline.tooltipped-s:after,
.tooltipped-multiline.tooltipped-n:after {
    right: auto;
    left: 50%;
    -webkit-transform: translateX(-50%);
    -ms-transform: translateX(-50%);
    transform: translateX(-50%)
}

TIP
 
 

현재 제 블로그의 복사 버튼에는 애니메이션 효과가 적용되어있습니다. 또한 코드블럭 복사 버튼 스타일은 본 블로그에 맞게 적용되어 있으니 사용자에 따라 알맞은 스타일을 수정하시는 것을 추천드립니다.
(애니메이션 효과를 적용하시고 싶으신 분께서는 여기를 눌러주세요.)

 

읽어주셔서 감사합니다🤟

 

 

 


잘못된 내용이 있으면 언제든 피드백 부탁드립니다.


서근


위처럼 이미지 와 함께 댓글을 작성할 수 있습니다.