코딩테스트 문제들을 풀다가 기록을 가끔씩 하고 있는데 hello스킨은 너무나 잘 만든 스킨이지만 코드블록은 너무 밋밋해서 뭐가 없을까 찾아보다가 너무 마음에 드는 디자인과 적용법을 찾았다.
https://guiyomi.tistory.com/132
[티스토리 블로그 테마] - 1. 코드 블록 디자인을 mac 코드 스타일로 바꾸기
글을 읽기 전 미리 보는 완성본은 다음과 같다. 어떻게 만들었고 적용했는지 궁금하신 분들은 아래로 스크롤! See the Pen tistory code block by MiJeong Kim (@sap03110) on CodePen. 발단 여느 날과 다름없이 회사
guiyomi.tistory.com
위의 블로그에 가면 HTML, CSS, JS 어떻게 수정해야 하는지 기본적으로 나와있다.
너무 마음에 들어서 바로 적용하려고 위에서 제시해주신 대로 따라했으나 hello 스킨을 사용하고 있어서 그런지 적용이 안되는 문제가 발생
혹시나 해서 hello스킨을 없애고 기본 티스토리에 적용하니까 바로 적용이 됐다. -> hello스킨에서 뭔가 안되는 이유가 있는듯?
그래도 맥코드블록을 쓰기 위해 위해 처음 적용을 하게 되면
이런식으로 코드가 깨지는 문제가 발생해서, 어떤 문제인지 찾아보니까
만드신 분의 코드블록은
이런식으로 code-header와 code-body가 따로 적용이 되어야 하는데,
내 코드를 보면
이런식으로 code-header와 code-body가 적용이 안된 것을 볼 수 있다.
여기서 헤더와 바디를 바꿔주는 부분이 어딨는지 찾아보니 위 블로그에 첨부되어있던
codeblock.js 파일을 보면
const COPY_TEXT_CHANGE_OFFSET = 1000;
const COPY_BUTTON_TEXT_BEFORE = 'Copy';
const COPY_BUTTON_TEXT_AFTER = 'Copied';
const COPY_ERROR_MESSAGE = '코드를 복사할 수 없습니다. 다시 시도해 주세요.';
const codeBlocks = document.querySelectorAll('code');
const copyBlockCode = async (target = null) => {
if (!target) return;
try {
const code = decodeURI(target.dataset.code);
console.log("-----");
console.log(code);
console.log("-----");
await navigator.clipboard.writeText(code);
target.textContent = COPY_BUTTON_TEXT_AFTER;
setTimeout(() => {
target.textContent = COPY_BUTTON_TEXT_BEFORE;
}, COPY_TEXT_CHANGE_OFFSET);
} catch(error) {
alert(COPY_ERROR_MESSAGE);
console.error(error);
}
}
for (const codeBlock of codeBlocks) {
const codes = codeBlock.innerHTML.match(/(.*)(\n|.*$)/g);
const processedCodes = codes.reduce((prevCodes, curCode) => prevCodes +
`<div class="line">${curCode}</div>`, '');
console.log(codes);
console.log("here");
const copyButton = `<button type="button" class="copy-btn"
data-code="${encodeURI(codeBlock.textContent)}"
onclick="copyBlockCode(this)">${COPY_BUTTON_TEXT_BEFORE}</button>`;
const codeBody = `<div class="code-body">${processedCodes}</div>`;
const codeHeader = `
<div class="code-header">
<span class="red btn"></span>
<span class="yellow btn"></span>
<span class="green btn"></span>
${copyButton}
</div>`;
codeBlock.innerHTML = codeHeader + codeBody;
}
이렇게 헤더와 바디를 넣어 주는 부분이 있다.
왜 적용이 안된걸까 찾아보면서 codeblock.js 파일에서 codeBlocks의 내용을 출력해봤는데 js 파일로 실행할땐 pre > code 부분이 null로 표기되었고, 직접 크롬 콘솔에 똑같이 검색하니까 결과값이 나왔다. -> document.querySelector로 code 부분을 못 찾는 문제 인지
다시 구글링을 통해서 찾아본 결과 HTML이 완전히 로드 되기 전에 JavaScript 파일을 실행해서 pre > code 부분이 null로 표기 되었었다.
HTML을 완전히 로드하고 JavaScript 파일을 실행하기 위해선 여러 가지 방법이 있는데,
GPT가 알려준 방법들은 이러하다.
둘다 적용해봤지만 역시 실패
그래서 결국 찾은 방법은 Alpine.js라는 마크업툴을 이용해서 해결하는 방법이다. 아마 잘은 모르지만 hello스킨이 이 툴을 통해서 만들어져있는 것 같은데, 여기서 Alpine.start();라는 명령어를 사용하면 원하는 타이밍에 JavaScript를 실행할 수 있어서. HTML이 로드되고 나서 실행되도록 수정하면 된다.
서론이 길었는데, 결과만 정리하자면
결과
👉 - HTML
티스토리 스킨 편집에 들어가서
<body>의 제일 최하단에 해당 스크립트 코드 추가
.
.
.
</s_t3>
<script>
document.addEventListener("DOMContentLoaded", function () {
Alpine.start();
const COPY_TEXT_CHANGE_OFFSET = 1000;
const COPY_BUTTON_TEXT_BEFORE = 'Copy';
const COPY_BUTTON_TEXT_AFTER = 'Copied';
const COPY_ERROR_MESSAGE = '코드를 복사할 수 없습니다. 다시 시도해 주세요.';
const codeBlocks = document.querySelectorAll('pre > code');
const copyBlockCode = async (target = null) => {
if (!target) return;
try {
const code = decodeURI(target.dataset.code);
await navigator.clipboard.writeText(code);
target.textContent = COPY_BUTTON_TEXT_AFTER;
setTimeout(() => {
target.textContent = COPY_BUTTON_TEXT_BEFORE;
}, COPY_TEXT_CHANGE_OFFSET);
} catch(error) {
alert(COPY_ERROR_MESSAGE);
console.error(error);
}
}
for (const codeBlock of codeBlocks) {
const codes = codeBlock.innerHTML.match(/(.*)(\n|.*$)/g);
const processedCodes = codes.reduce((prevCodes, curCode) => prevCodes +
`<div class="line">${curCode}</div>`, '');
const copyButton = `<button type="button" class="copy-btn"
data-code="${encodeURI(codeBlock.textContent)}"
onclick="copyBlockCode(this)">${COPY_BUTTON_TEXT_BEFORE}</button>`;
const codeBody = `<div class="code-body">${processedCodes}</div>`;
const codeHeader = `
<div class="code-header">
<span class="red btn"></span>
<span class="yellow btn"></span>
<span class="green btn"></span>
${copyButton}
</div>`;
codeBlock.innerHTML = codeHeader + codeBody;
}
});
</script>
</body>
👉 - CSS
CSS -> hljs 부분 수정
/* #content .contents_style pre code.hljs {
--tw-bg-opacity: 1;
background-color: rgb(244 244 246 / var(--tw-bg-opacity))
}
.dark #content .contents_style pre code.hljs {
--tw-bg-opacity: 1;
background-color: rgb(41 42 45 / var(--tw-bg-opacity))
} */
pre {
position: relative;
}
pre::after {
content: attr(data-ke-language);
position: absolute;
bottom: 8px;
right: 12px;
color: #cfd2d1;
font-size: 12px;
}
#content .hljs {
display: flex !important;
flex-direction: column;
padding: 0 !important;
font-size: 14px;
border-radius: 8px;
box-shadow: 0 12px 24px rgb(0 0 0 / 40%);
color: #cfd2d1;
background-color: rgb(40 44 52);
font-family: Menlo, Courier, monospace;
}
#content .hljs .line {
counter-increment: line-idx;
line-height: 1.5;
}
#content .hljs .line:hover {
background-color: #262830;
}
#content .hljs .line:hover::before {
color: #cfd2d1;
}
#content .hljs .line::before {
content: counter(line-idx);
width: 24px;
display: inline-block;
text-align: right;
margin-right: 16px;
font-size: 0.8rem;
color: #747a7a;
}
#content .hljs .code-header {
display: flex;
align-items: center;
padding: 14px;
background-color: #434041;
border-radius: 8px 8px 0 0;
}
#content .hljs .code-header .btn {
border-radius: 50%;
width: 15px;
height: 15px;
margin: 0 5px;
}
#content .hljs .code-header .btn.red {
background-color: #f5655b;
}
#content .hljs .code-header .btn.yellow {
background-color: #f6bd3b;
}
#content .hljs .code-header .btn.green {
background-color: #43c645;
}
#content .hljs .code-body {
max-height: 600px;
margin: 32px 8px;
overflow: auto;
}
#content .hljs .code-body::-webkit-scrollbar {
width: 12px;
}
#content .hljs .code-body::-webkit-scrollbar-thumb {
background-color: rgb(1 2 3 / 80%);
border-radius: 4px;
}
#content .hljs .code-body::-webkit-scrollbar-corner {
display: none;
}
#content .hljs .copy-btn {
background-color: transparent;
border: none;
cursor: pointer;
color: #fff;
font-size: 0.75rem;
padding: 6px 0;
width: 64px;
border-radius: 4px;
margin-left: auto;
transition: 0.2s background-color;
}
#content .hljs .copy-btn:hover {
background-color: #555152;
}
🚨 이렇게 추가해도 본문 내용이 2번 반복해서 나오는 이슈가 있는데 해당 부분은
hello스킨을 처음 적용할 때 업로드했던 script 파일이 있는데 해당 script 파일을 열어서 마지막 줄을 보면 Alpine.start()를 해주는 부분이 있는데 이 부분이 중복되어 있어서 2번 로드되는 오류가 발생했음
그래서 script파일의 마지막 부분을 주석처리 하고 다시 업로드하면 끝
document.addEventListener('alpine:init', function() {
return Alpine.data('theme', function() {
return {
/**
* Toggle Theme
*/
toggle: function toggle() {
localStorage.TTDARK = document.documentElement.classList.contains('dark') ? 'N' : 'Y';
document.documentElement.classList.toggle('dark');
this.$data.dark = !this.$data.dark;
}
};
});
});
// --> 이 부분 주석처리
//window.addEventListener('DOMContentLoaded', function() {
// return Alpine.start();
//});
요약하자면 (다른 파일들을 추가하고 업로드 할 필요 없이)
1. HTML에 위 코드 추가
2. CSS 수정
3. 업로드된 script.js 파일 마지막 부분 주석처리
더 간단한 방법이 있다면 공유 부탁드립니다.