hexo+icarus 다크모드 깜빡임 해결

예전에 메모해놓고 이제 게시글로 적는다!

기본 배경 색 없애기

먼저 css레벨에서 적용되는 css를 초기화해야한다.
브라우저는 기본적으로 css가 없을 시 페이지 이동할 때 이전 페이지의 배경색을 그대로 유지한다.

\theme\icarus\css\include\style\base.styl
7줄 기본 배경색 none으로 수정하기

1
$body-background-color ?= none;

기존 js파일을 두 개로 나누기

로컬스토리지를 읽고 다크모드를 적용하는 함수와 html을 전부 로드한 후 버튼의 innerText를 수정하는 함수로 나누었다.

다크모드를 적용하는 함수는 render blocking이 이루어져야하고 버튼의 innerText의 수정은 HTML이 모두 로드 후 이루어져야하기 때문이다.

따라서 버튼을 수정하는 함수는 defer로 불러오고 다크모드를 확인하고 적용하는 함수는 속성 없는 script태그로 불러온다.

\themes\icarus\source\js\darkmode.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function init() {
const darkScheme = window.matchMedia("(prefers-color-scheme:dark)");
const theme = localStorage.getItem("theme");
if (theme === "dark") {
document.body.classList.add("dark");
return;
}
if (theme === "light") {
return;
}

if (darkScheme) document.body.classList.add("dark");

localStorage.setItem("theme", darkScheme ? "dark" : "light");
}

hexo\themes\icarus\source\js\darkmodebutton.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const darkModeButton = document.querySelector("#changeModeButton");
const darkScheme = window.matchMedia("(prefers-color-scheme:dark)");

darkScheme.addEventListener("change", (e) => {
console.log("hidark");
const newColorScheme = e.matches ? "dark" : "light";
localStorage.setItem("theme", newColorScheme);

if (newColorScheme === "dark") {
document.body.classList.add("dark");
btn.innerText = "🌙";
return;
}
document.body.classList.remove("dark");
btn.innerText = "🌞";
});

function toggleTheme() {
console.log("hibutton");
document.body.classList.toggle("dark");
darkModeButton.innerText = document.body.classList.contains("dark")
? "🌙"
: "🌞";
localStorage.setItem(
"theme",
document.body.classList.contains("dark") ? "dark" : "light"
);
}

function initButton() {
console.log("initButton");
const data = localStorage.getItem("theme");
if (data == "dark") {
darkModeButton.innerText = "🌙";
return;
}
darkModeButton.innerText = "🌞";
}

initButton();
darkModeButton.addEventListener("click", toggleTheme);

\themes\icarus\layout\common\scripts.jsx
56번쨰 줄에 darkmodebutton.js추가

1
2
<script src={url_for("/js/main.js")} defer></script>
<script src={url_for("/js/darkmodebutton.js")} defer></script>

hexo\themes\icarus\layout\common\head.jsx

js를 로드하고 실행하는 동안 렌더링을 막아야하기 때문에 script에 속성을 지정하지 않아야한다.
적다보니 preload속성을 추가해도 좋을 것 같다.

1
<script src={url_for("/js/darkmode.js")}></script>

고의로 render blocking 만들기

새로고침이 되어서 다크모드가 적용되기 전 까지 렌더링이 이루어지면 안된다.

body의 최상단에 darkmode.js에서 정의한 init함수를 호출해준다.
hexo\themes\icarus\layout\layout.jsx

1
2
3
4
<html lang={language ? language.substr(0, 2) : ""}>
<Head site={site} config={config} helper={helper} page={page} />
<body class={`is-${columnCount}-column`}>
<script>init();</script>

ref

https://www.youtube.com/watch?v=ElsZ-v4Ow08

hexo + github 블로그 다크모드 깜빡임 해결

렌더링이 시작된 후에 defer속성으로 받아온 스크립트가 실행되다보니 화면 전환중에 흰화면으로 잠시 전환되는 현상이 발생하였다.

다음과 같은 방법으로 수정하였다.

body의 기본 배경 색 없애기

먼저 7번째 줄에 있는 body의 background-color를 none으로 수정하였다.

\theme\icarus\css\include\style\base.styl

1
$body-background-color ?= none;

기존 js파일을 두 개로 나누기

기존 js파일의 경우 init 함수에서 버튼 설정과 다크모드 로드를 동시에 해주었는데,
다크모드 로드는 렌더링 전에 실행되어야 하고 버튼 설정은 렌더링 후에(최소 DOM트리 생성 이후) 실행되어야 한다.
때문에 파일을 두 개로 나누었다.

darkmode.js엔 chinsun9님의 게시글을 읽고 matchMedia를 읽어서 실행하는 부분을 추가하였다.
(너무 친절하게 답변해주셨다..!)

localstorage와 matchMedia를 이용하여 다크모드를 로드하는 함수이다.
\themes\icarus\source\js\darkmode.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function init() {
const darkScheme = window.matchMedia("(prefers-color-scheme:dark)");
const theme = localStorage.getItem("theme");
if (theme === "dark") {
document.body.classList.add("dark");
return;
}
if (theme === "light") {
return;
}

if (darkScheme) document.body.classList.add("dark");

localStorage.setItem("theme", darkScheme ? "dark" : "light");
}

버튼 관련 설정을 하는 js 파일이다.
hexo\themes\icarus\source\js\darkmodebutton.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const darkModeButton = document.querySelector("#changeModeButton");
const darkScheme = window.matchMedia("(prefers-color-scheme:dark)");

darkScheme.addEventListener("change", (e) => {
console.log("hidark");
const newColorScheme = e.matches ? "dark" : "light";
localStorage.setItem("theme", newColorScheme);

if (newColorScheme === "dark") {
document.body.classList.add("dark");
btn.innerText = "🌙";
return;
}
document.body.classList.remove("dark");
btn.innerText = "🌞";
});

function toggleTheme() {
console.log("hibutton");
document.body.classList.toggle("dark");
darkModeButton.innerText = document.body.classList.contains("dark")
? "🌙"
: "🌞";
localStorage.setItem(
"theme",
document.body.classList.contains("dark") ? "dark" : "light"
);
}

function initButton() {
console.log("initButton");
const data = localStorage.getItem("theme");
if (data == "dark") {
darkModeButton.innerText = "🌙";
return;
}
darkModeButton.innerText = "🌞";
}

initButton();
darkModeButton.addEventListener("click", toggleTheme);

작성한 js파일의 위치 지정해주기

  1. darkmodebutton.js
    버튼은 렌더링후에(최소 DOM트리 생성 이후) 실행되어야 하므로 아래부분에 추가해주었다.
    \themes\icarus\layout\common\scripts.jsx
    56번쨰 줄에 darkmodebutton.js추가

    1
    2
    <script src={url_for("/js/main.js")} defer></script>
    <script src={url_for("/js/darkmodebutton.js")} defer></script>
  2. darkmode.js
    body 최상단에서 실행하기위해 head태그에서 js파일을 로드했다.
    적다보니 preload속성을 추가해도 좋을 것 같다.

    hexo\themes\icarus\layout\common\head.jsx

    1
    <script src={url_for("/js/darkmode.js")}></script>
  3. darkmode.js의 init 함수
    다크모드를 로드하는 건 렌더링 이전에 실행되어야한다.
    때문에 body태그 최상단에 rendering block 요소로 defer나 async 속성을 지정하지 않고 넣어주었다.
    hexo\themes\icarus\layout\layout.jsx

    1
    2
    3
    4
    <html lang={language ? language.substr(0, 2) : ""}>
    <Head site={site} config={config} helper={helper} page={page} />
    <body class={`is-${columnCount}-column`}>
    <script>init();</script>

ref

[A1] 웹뷰에서 다크모드 상속받기: 일관성있는 사용자 경험을 위하여
blog fix 다크 모드 화면 깜박임 제거

hexo + blog runMicroTasks 에러 해결하기

hexo generate중에 에러가 발생했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
FATAL {
err: Error: ** Processing: C:\Users\SDPark-pc\AppData\Local\Temp\f657ac55-7bfc-474b-8bd4-783a7a740fb7
1024x1024 pixels, 4x8 bits/pixel, RGB+alpha
Input IDAT size = 16536 bytes
Input file size = 16593 bytes

Trying:
zc = 9 zm = 8 zs = 0 f = 0 IDAT size = 16536
zc = 9 zm = 8 zs = 3 f = 0 0
at C:\Users\SDPark-pc\Desktop\REACT\blog\hexo\node_modules\exec-buffer\node_modules\execa\index.js:231:11
at runMicrotasks (<anonymous>)
at processTicksAndRejections (internal/process/task_queues.js:93:5) {
code: 3221225477,
killed: false,
stdout: '',
stderr: '** Processing: C:\\Users\\SDPark-pc\\AppData\\Local\\Temp\\f657ac55-7bfc-474b-8bd4-783a7a740fb7\r\n' +
'1024x1024 pixels, 4x8 bits/pixel, RGB+alpha\r\n' +
'Input IDAT size = 16536 bytes\r\n' +
'Input file size = 16593 bytes\r\n' +
'\r\n' +
'Trying:\r\n' +
' zc = 9 zm = 8 zs = 0 f = 0\t\tIDAT size = 16536\r\n' +
' zc = 9 zm = 8 zs = 1 f = 0\r zc = 1 zm = 8 zs = 2 f = 0\r zc = 9 zm = 8 zs = 3 f = 0',
failed: true,
signal: null,
cmd: 'C:\\Users\\SDPark-pc\\Desktop\\REACT\\blog\\hexo\\node_modules\\hexo-filter-cleanup\\node_modules\\optipng-bin\\vendor\\optipng.exe -strip all -clobber -fix -o 2 -out C:\\Users\\SDPark-pc\\AppData\\Local\\Temp\\044b15b2-8a65-4748-97c3-ad4280ef2c14 C:\\Users\\SDPark-pc\\AppData\\Local\\Temp\\f657ac55-7bfc-474b-8bd4-783a7a740fb7',
timedOut: false
}
} Something's wrong. Maybe you can find the solution here: %s https://hexo.io/docs/troubleshooting.html

hfc에서 발생한 에런지 hexo에서 발생한 에러인지 모르지만 해결하였다.

다음과 같이 execa라는 모듈을 재설치 해주었다.

1
2
npm rm execa
npm i execa

hexo +github 블로그 Spawn failed 에러 해결하기

블로그 포스팅을 하던 중에 다음과 같은 에러가 발생하였다.

1
2
3
4
5
Error: Spawn failed
at ChildProcess. (D:\blog\node_modules\hexo-util\lib\spawn.js:51:21)
at ChildProcess.emit (events.js:311:20)
at ChildProcess.cp.emit (D:\blog\node_modules\cross-spawn\lib\enoent.js:34:29)
at Process.ChildProcess.\_handle.onexit (internal/child_process.js:275:12)

deploy 자체가 안 되어서 헤메던 중에 해결방안을 발견하였다.

.deploy*git에서 index.lock 파일을 삭제하니까 해결되었다.
directory

ref

https://blog.zhheo.com/p/128998ac.html

카탈로그 수정

카탈로그의 위치를 수정하였다.

카탈로그는 아래 사진의 오른쪽에 저렇게 목차가 나오고 클릭할 경우 해당 부분으로 이동하는 위젯이다.

image

처음엔 카탈로그가 왼 쪽에 있고 고정되지 않아, 글의 목차와 내용을 간략하게 보려고 할 경우 카탈로그가 존재하는 위치까지 이동해주어야 했다.

카탈로그를 오른쪽에 배치하고 고정되도록 만들기로 하였다.

코드 살펴보기

개발자 도구를 열어 카탈로그에 position: fixed와 position:sticky를 추가해주었다.

왼쪽에 있는 다른 위젯들과 겹쳐 가독성이 상당히 안 좋았다.

레이아웃의 html을 살펴보았다.

image

게시글이 작성된 부분의 css이다.

1
"column order-2 column-main is-9-tablet is-9-desktop is-9-widescreen"

왼 쪽부터 클래스명의 order-1, order-2 등으로 레이아웃을 정하는 듯 하였다.

또한 is-9-tablet 과 같은 클래스는 기기마다 차지할 크기를 알려주는 클래스명이다.

개발자도구에서 클래스명이 column 상위 태그에 다음과 같은 HTML을 추가해 보았다.

1
<div class="column order-3 column-main is-9-tablet is-9-desktop is-9-widescreen">hihi</div>

성공적으로 추가되었다.
image

레이아웃 수정하기

성공한 줄 알았으나 실제 카탈로그에 적용하니 레이아웃 밖으로 나갔다 ㅠ

클래스명을 살펴보니 클래스명을 통해 설정한 레이아웃과 위젯의 비율이 오버한 것 같았다.

nav-bar를 아래의 영역은 hexo\themes\icarus\layout\layout.jsx에서 관리된다.

총 column의 합이 12가 되도록 수정해주어야 한다.

columncount가 1일 경우 12 2일 경우 9 3일 경우 8을 사용하도록 수정해주었다.

image

위젯 수정하기

hexo\themes\icarus\layout\common\widgets.jsx또한 수정해주었다.

우측에 카탈로그를 추가하게 되면 column count가 왼쪽 위젯 게시글 오른쪽 위젯으로 3이 된다.

위에서 3일경우 8을 사용하도록 수정해주었기 때문에 3일때의 위젯의 레이아웃 비율을 2를 사용하여 합이 총 12(8+2+2)가 되도록 수정해주었다.

image

sticky 적용하기

개발자 도구를 열고 position:sticky를 적용하니 잘 되지 않았다ㅠ

widgets.jsx 파일을 살펴보니 is-sticky라는 클래스명이 있었다. 이를 개발자도구에 적용하니 제대로 작동하였다.

파일에서 찾아서 수정하려하니 생각보다 어려웠다.

그러던 중 widgets.jsx 파일을 살펴보니 columncount가 3이면 제일 오른쪽에 있는 모듈을 보이지 않게 해주는 함수를 찾았다.

내 경우 오른쪽에는 카탈로그 밖에 없고, 오른쪽에 다른 위젯이 있을 경우 겹치거나 보이지 않아서 가독성이 좋지 않다.

그래서 이부분에 is-sticky를 추가해주었다.

image

완성본

카탈로그

정상적으로 작동하게 되었다..!

hexo+ icarus 다크모드 구현하기

나는 다크모드를 아주 애용한다.

다크모드를 적용하며 유익한 경험이여서 글로 작성해두려고 한다.

hexo + icarus 작동원리

우선 hexo + icarus의 원리부터 알아야한다.

아래에 작성할 모든 디렉터리는 hexo루트 폴더 기준이다.

루드 디렉토리의 내부 파일을 수정한다.

그 후 정적파일인 public 폴더를 생성하고 배포하면 사이트에 반영되는 구조이다.

1
hexo generate --deploy

커스텀 디자인을 하기 위해선 이 ./themes 폴더를 수정해야한다.

버튼 만들기

./themes/icarus/layout/common 폴더엔 icarus의 여러 요소들의 jsx파일이 작성되어있다.

hexo\themes\icarus\layout\common\navbar.jsx파일에서 검색버튼 옆에 버튼을 만들었다.

1
<button type="button" id="changeModeButton" class="navbar-item" />

버튼을 커스텀하기

./themes/icarus/include/style 폴더엔 여러 css들이 작성되어있다.

확장자가 styl인데 기존에 작성된 파일을 보니 들여쓰기로 depth를 관리하는 듯 했다.

그리고 이 파일들은 ./themes/source/css/style.styl에서 모두 import되고 이를 빌드하여 ./public/css에 하나의 css파일을 생성한다.

./themes/icarus/include/style/navbar.styl 파일에 다음과 같은 내용을 추가하였다.

1
2
3
4
5
6
#changeModeButton {
background: none;
border: none;
cursor: pointer;
font-size: 2rem;
}

버튼에 로직 추가하기

./themes/source/js 폴더엔 여러 js파일들이 있다.

이는 ./themes/icarus/layout/common/scripts.js에서 한 번에 모아서 ./public/index.js에 작성된다.

여기에 다크모드 버튼 관련 파일을 작성하였다.

페이지에 접속 시 로컬스토리지를 확인하고 darkMode가 true일경우 html의 body에 darkMode 태그를 추가하고 버튼의 모양을 달 모양으로 해주었다.

값이 존재하지 않을경우 버튼의 모양을 해 모양으로 해주었다. 기본 값은 다크모드의 미적용이기 때문에 따로 처리를 해주진 않았다.

그리고 버튼에 이벤트를 등록해주었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
const darkModeButton = document.querySelector("#changeModeButton");

function init() {
loadDarkModeData();
darkModeButton.addEventListener("click", clickEvent);
}

const loadDarkModeData = () => {
const data = localStorage.getItem("darkMode");
const body = document.querySelector("body");
if (data === "true") {
darkModeButton.innerText = "🌙";
body.classList.add("darkMode");
} else {
darkModeButton.innerText = "🌞";
}
};

const setDarkMode = () => {
const body = document.querySelector("body");
if (body.classList.contains("darkMode")) {
darkModeButton.innerText = "🌞";
body.classList.remove("darkMode");
localStorage.setItem("darkMode", false);
} else {
darkModeButton.innerText = "🌙";
body.classList.add("darkMode");
localStorage.setItem("darkMode", true);
}
};

const clickEvent = () => {
setDarkMode();
console.log(localStorage.getItem("darkMode"));
};

init();

그리고 ./themes/icarus/layout/common/scripts.js에 아래 내용을 추가해주었다.

정확히 어떤 구조인지는 모르지만 main.js가 이런 식으로 작성되어 있길래 똑같이 적었다.

defer는 script로딩시 버튼이 없으면 안되기 때문에 추가해주었다.

1
<script src={url_for("/js/darkmode.js")} defer></script>

다크모드 css 추가하기

다음으로 darkmode.styl 파일을 작성해주었다.

처음 보는 확장자명이기도 했고 ./themes/include/style에 작성할지 ./themes/source/css에 작성할지 고민되었다.

고민끝에 include폴더는 컴포넌트마다의 css를 작성하는 느낌이 강해서 ./themes/source/css/darkmode.styl에 작성하였다.

css는 개발자 도구를 여러 하나하나 클래스명을 확인하며 적어주었다.

빌드과정에서 압축될 것이여서 하나씩 풀어 적었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
body.darkMode
background-color: #171717;
color:#F9F9F9;
.navbar ,& .navbar-menu
background-color: #444444;
section,article,.card{
background-color: inherit;
color:inherit;
}
& .navbar-item
color:#F9F9F9;
&:hover{
color:#3273dc;
background-color:#393E46;
}
& .menu-list>li *{
color:rgba(255,255,255,0.9);
}

& .menu-list a:hover{
color:#3273dc;
background-color:#393E46;
}

& .menu-list a.is-active{
background:#141010;
}
& .is-active
color:#3273dc;
& article
& > * {
color:rgba(255,255,255,0.7);
};
& h1,h2,h3,h4,h5,h6{
color:rgba(255,255,255,0.9);
}
& .article-meta{
color:rgba(255,255,255,0.38);
}
& .card-content
& > * {
color:rgba(255,255,255,0.7);
};

& .title, .location{
color:rgba(255,255,255,0.9);
}

& .menu{
color:rgba(255,255,255,0.7);
}

& .level-start{
color:rgba(255,255,255,0.7);
}

& .menu-label{
color:rgba(255,255,255,0.9);
}

& .tag{
background:#444444;
color:rgba(255,255,255,0.7);
}
.searchbox-container
background:#444444;
.searchbox-input, .searchbox-close{
background:#444444;
color:rgb(255,255,255);
}
.footer{
background:#444444;
}
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #abb2bf;
background: #282c34;
}

.hljs-comment,
.hljs-quote {
color: #5c6370;
font-style: italic;
}

.hljs-doctag,
.hljs-keyword,
.hljs-formula {
color: #c678dd;
}

.hljs-section,
.hljs-name,
.hljs-selector-tag,
.hljs-deletion,
.hljs-subst {
color: #e06c75;
}

.hljs-literal {
color: #56b6c2;
}

.hljs-string,
.hljs-regexp,
.hljs-addition,
.hljs-attribute,
.hljs-meta-string {
color: #98c379;
}

.hljs-built_in,
.hljs-class .hljs-title {
color: #e6c07b;
}

.hljs-attr,
.hljs-variable,
.hljs-template-variable,
.hljs-type,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-number {
color: #d19a66;
}

.hljs-symbol,
.hljs-bullet,
.hljs-link,
.hljs-meta,
.hljs-selector-id,
.hljs-title {
color: #61aeee;
}

.hljs-emphasis {
font-style: italic;
}

.hljs-strong {
font-weight: bold;
}

.hljs-link {
text-decoration: underline;
}


그리고 ./themes/source/css/style.styl에 import 해주었다.

1
@import './darkmode.styl'

정리

전체적인 로직은 다음과 같다.

  1. body.darkMode의 하위 태그들에 적용이 되도록 여러 css를 작성해둔다.
  2. 첫 접속시에 로컬스토리지에 darkMode 관련 값이 저장되어있는지 확인하고 알맞은 처리를 해준다. 새로고침시에 상태가 유지되게 하기 위함이다.
  3. 버튼 클릭시 다크모드가 적용되도록 이벤트를 추가해준다.(body태그에 darkMode 클래스를 toggle하도록)

완성본

다크모드가 적용될 경우 적용되지 않을경우의 버튼이 다르고 글자 색과 배경 색도 다르다.

다크모드 미적용 다크모드 적용

느낀 점

  1. styl 확장자 파일을 작성해보았다.
    • Stylus CSS파일이라고 하는데, 작성해보니 의외로 굉장히 편하였다.
  2. REACT가 아닌 jsx로 작성되어 이러한 파일들을 중앙에서 제어하여 빌드시 html을 만드는 과정에 대한 이해가 늘었다.
    • jsx문법을 이용하여 컴포넌트 단위로 파일을 작성하고 관리하는 것이 얼마나 가독성이 좋은지 다시 한 번 느꼈다.
  3. 역시 다크모드가 눈이 편하다
    • 다크모드가 최고다 ㅠ

아쉬운 점

  1. 구현을 하고 보니 코드블록이나 위젯에는 다크모드가 적용이 안 되었다.
    • 이것도 개발자 도구를 이용하여 css를 까보고 수정해야겠다.
  2. 모바일에서 레이아웃이 아쉽다.
    • 버튼을 추가하다보니 상단바에 스크롤바가 생겼다.
    • 이것도 수정해보아야겠다. 레이아웃에 손을 대거나 전체적으로 크기를 줄이는 방향으로 갈 것 같다.
    • 모바일
  3. 정신없이 작업하고 복기하며 메모하다보니 빠진 부분이 있을까봐 걱정된다.
    • 다음부턴 간략한 개요든지 사진을 틈틈히 찍어두어야겠다 ㅠ

+++ 수정

다크모드를 끄고 게시글에 접근시 다크모드가 적용되는 버그가 있었다.
로컬스토리지에 데이터가 string으로 저장되는데 if(data)의 형태로 확인해서 발생한 버그였다.

1
2
3
4
5
6
7
8
9
10
const loadDarkModeData = () => {
const data = localStorage.getItem("darkMode");
const body = document.querySelector("body");
if (data) {
darkModeButton.innerText = "🌙";
body.classList.add("darkMode");
} else {
darkModeButton.innerText = "🌞";
}
};

위 부분을 다음과 같이 변경하였다.

1
2
3
4
5
6
7
8
9
10
const loadDarkModeData = () => {
const data = localStorage.getItem("darkMode");
const body = document.querySelector("body");
if (data === "true") {
darkModeButton.innerText = "🌙";
body.classList.add("darkMode");
} else {
darkModeButton.innerText = "🌞";
}
};

hexo+icarus 위젯 삭제하고 댓글 기능 추가하기

위젯 없애기

블로그 내에서 표시되는 위젯들은 루트디렉토리의 _config.icarus.yml에서 수정 가능하다.

수정하려면 윗줄의 -를 포함하여 다음 -까지 위젯 관련 정보들을 지워주면 된다.
주석 줄에 있어서 -도 주석인 줄 알고 안 지웠더니 빌드에 실패하였다.
나는 카테고리나 태그같은 게시글 관련 위젯 말고는 전부 지워주었다.

위젯 윗부분에 donation도 삭제 해주었다.

1
2
3
4
- # 주석
position: ''
type: ''
(...)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# Table of contents widget configurations

- # Where should the widget be placed, left sidebar or right sidebar
position: right
type: toc
# Whether to show the index of each heading
index: true
# Whether to collapse sub-headings when they are out-of-view
collapsed: true
# Maximum level of headings to show (1-6)
depth: 3

# Recommendation links widget configurations

# Categories widget configurations

- # Where should the widget be placed, left sidebar or right sidebar
position: left
type: categories

# Recent posts widget configurations

- # Where should the widget be placed, left sidebar or right sidebar
position: left
type: recent_posts

# Archives widget configurations

- # Where should the widget be placed, left sidebar or right sidebar
position: left
type: archives

# Tags widget configurations

- # Where should the widget be placed, left sidebar or right sidebar
position: left
type: tags

댓글 기능 추가

disqus를 이용하였다.

사용방법이 무척 간단하다.

  1. disqus 접속한다.

    홈페이지
  2. I want to instal …를 클릭한다.

    선택 페이지
  3. 웹사이트 명을 입력해준다.
    이 정보는 shortname에 사용된다.
    아래의 shortname을 복사해둔다.

    설정하기
  4. Basic 요금제를 구독한다.

    무료 요금제를 고른다.
  5. Universal Code를 선택한다.

    목록에 없다 ㅠ
  6. icarus엔 shortname만 필요하다.
    configure를 눌러 다음으로 가고 정보를 입력해준다.
    website URL을 채워주면 된다.

    정보를 입력한다.
  7. 정책을 골라준다.
    큰 차이점은 basic은 비로그인 댓글도 허용하고
    strict는 로그인 댓글만 허용한다.
    다만 google, twitter, facebook 자동로그인을 사용할 수 있다.
    나는 strict을 골라주었다.

    정책
  8. dismiss를 누르고 hexo 루트디렉토리의 _config.icarus.yml 파일을 수정한다.

    1
    2
    3
    4
    5
    6
    comment:
    type: disqus
    # Disqus shortname
    shortname: "shortname"
    # Donate plugin configurations
    # https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/Donation/
  9. 변경사항을 적용한다.

1
hexo clean & hexo generate --deploy & git add . & git commit -m "메시지" & git push origin main
  1. 변경사항이 적용되었음을 확인할 수 있다..!

hexo에서 이미지 업로드하기

++ 수정

아래의 방법은 간단하지만 랜더링 최적화를 위해선 정적 이미지파일을 사용하는 것을 추천합니다!

hexo는 Markdown으로 게시글을 작성한다. 때문에 이미지를 업로드 하는 과정이 쉽지 않다.

hexo-icarus테마-수정하기 게시글을 작성하며 사진을 업로드 할 때는

_posts의 상의 폴더인 source 폴더에 img 폴더를 만들고 거기에 이미지를 저장해서 img태그src속성에 상대경로를 적어 사용하였다.

이렇게 하니 home으로 접근할 때는 정상적으로 이미지를 출력하지만 tag 탭이라든지 경로가 바뀌면 이미지가 다음과 같이 깨졌다.

이미지가 깨졌어요

어떻게 해결할지 고민하다가 hexo 소스들을 정리해둔 private 레포가 생각났다.

블로그 관련 레포에 모든 정보를 모아서 관리하면 수월할 것이라 생각해 issue탭에 이미지를 업로드하고(깃허브 서버에 올린 뒤) 이 링크를 받아서 사용하였다.

그랬더니 현재 경로와 상관없이 정상적으로 이미지 출력에 성공하였다.

하지만 이미지를 하나씩 업로드 하는 방식이 효율적이진 않은데, 다음에 이미지를 업로드 할 때는 레포에 업로드 해보고 이용할 수 있는지 해봐야겠다.

hexo icarus 테마 내 정보 수정하기

Icarus 테마를 이용해 배포는 완료했지만 블로그가 예쁘지 못하다.
또한 사이트 내에 표시되는 내 정보를 수정해주었다.
이를 수정해주었다.

hexo에는 두 개의 yml 파일이 있다.
_config.yml 파일과 _config.icarus.yml파일이다.

사이트 제목 바꾸기

_config.yml에선 웹페이지에 대한 정보를 설정할 수 있다.
_config.yml의 # Site를 다음과 같이 수정해주었다.

1
2
3
4
5
6
7
8
# Site
title: 개발 블로그
subtitle: ""
description: 프론트엔드를 공부하고 있습니다.
keywords:
author: 박성현
language: ko
timezone: "Asia/Seoul"

favicon과 홈버튼 바꾸기

_config.yml에선 favicon과 icon도 설정할 수 있다.

1
2
3
4
5
6
7
8
9
10
# Version of the configuration file
version: 4.0.0
# Icarus theme variant, can be "default" or "cyberpunk"
variant: default
# Path or URL to the website's logo
logo: /img/logo.svg
# Page metadata configurations
head:
# URL or path to the website's icon
favicon: /img/favicon.svg

나는 themes/icarus/source/iimg의 favicon.svg와 logo.svg파일을 아주귀여운강아지에서 찾아 svg를 바꾸어 주었다.

_config.yml에 대한 더 많은 정보는 Hexo 공식문서에서 찾아볼 수 있다.

자기소개와 설명 바꾸기

위에서 소개와 이름을 작성해도 실제 사이트에 접속하면 자기소개에 반영되지 않는다
_config.yml에서 설정한 정보들은 다음 그림과 같이 <head>태그에 들어간다

head tag

사이트에 표시될 정보들은 _config.icarus.yml 에서 설정해주어야 한다.
_config.icarus.yml 파일을 다음과 같이 수정해주었다.

깃허브와 facebook등은 천천히 수정할 예정이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
widgets:
# Profile widget configurations
- # Where should the widget be placed, left sidebar or right sidebar
position: left
type: profile
# Author name
author: 박성현
# Author title
author_title: 프론트엔드를 공부하고 있습니다
# Author's current location
location: Seoul
# URL or path to the avatar image
avatar: /img/profile.webp
# Whether show the rounded avatar image
avatar_rounded: true
# Email address for the Gravatar
gravatar:
# URL or path for the follow button
# Links to be shown on the bottom of the profile widget
social_links:
Github:
icon: fab fa-github
url: "https://github.com/pshdev1030"
Linkedin:
icon: fab fa-linkedin
url: "https://www.linkedin.com/in/pshdev1030"
# Table of contents widget configurations
- # Where should the widget be placed, left sidebar or right sidebar
position: right
type: toc
# Whether to show the index of each heading
index: true
# Whether to collapse sub-headings when they are out-of-view
collapsed: true
# Maximum level of headings to show (1-6)
depth: 3
# Recommendation links widget configurations
# Categories widget configurations
- # Where should the widget be placed, left sidebar or right sidebar
position: left
type: categories
# Recent posts widget configurations
- # Where should the widget be placed, left sidebar or right sidebar
position: left
type: recent_posts
# Archives widget configurations
- # Where should the widget be placed, left sidebar or right sidebar
position: left
type: archives
# Tags widget configurations
- # Where should the widget be placed, left sidebar or right sidebar
position: left
type: tags
# Google FeedBurner email subscription widget configurations
# Google AdSense unit configurations
# Plugin configurations
# https://ppoffice.github.io/hexo-theme-icarus/categories/Plugins/

hexo +github를 이용하여 블로그 만들기

hexo와 github를 이용하여 블로그를 만들었다.

환경

  • node.js
  • github

Hexo 설치

1
npm install hexo-cli -g

원하는 디렉토리로 이동하여 hexo 초기설치를 해준다.

1
2
3
hexo init [블로그명]
cd [블로그명]
npm install

설치가 완료되면

1
hexo server

localhost:4000에 접속하여 확인할 수 있다.

icarus 테마 적용하기

[블로그명] 디렉토리의 thems 폴더에 가서 icarus repo를 clone한다.

1
2
cd ./themes
git clone https://github.com/ppoffice/hexo-theme-icarus.git

그리고 clone된 hexo-theme-icarus 폴더의 이름을 icarus로 바꾼다.

1
mv hexo-theme-icarus icarus

그리고 나서 로컬로 다시 실행한다

1
hexo server

에러가 뜨면 필요한 패키지들을 설치한다.
설치가 안 될 경우 –legacy-peer-deps 플래그를 붙인다.

1
npm install --save [모듈들]... --legacy-peer-deps

설치 후 로컬로 다시 실행하면 icarus 테마가 적용된다

  • 적용되지 않을 경우 ide를 껐다가 다시 킨 후 실행하면 된다.
1
hexo server

배포하기

깃허브는 사용자계정.github.io로 무료 호스팅된 페이지를 사용할 수 있게 해준다.

사용자계정.githob.io라는 이름의 저장소와 블로그 소스파일을 저장할 저장소 총 두 개의 저장소를 만든다.

그리고 Settings 페이지의 Github Pages 항목에서 Source 옵션을 Master or Main으로 설정한다.

다음 루트경로의 _config.yml 파일의 deploy항목을 다음과 같이 수정한다

1
2
3
4
deploy:
type: git
repo: https://github.com/사용자계정/사용자계정.github.io.git
branch: 브랜치명

배포를 위해선 플러그인도 설치해주어야 한다.

1
npm install --save hexo-deployer-git

정적 리소스 생성하고 배포하기

정적 리소스는 다음과 같이 생성한다.

1
hexo generate

배포는 다음과 같이 한다.

1
hexo deploy

정적 리소스를 삭제하는 명령어는 다음과 같다.
수정했는데 업데이트가 되지 않을 경우 사용하면 된다.

1
hexo clean

정적 리소스 생성 및 배포는 다음과 같이 하면 된다.

1
hexo deploy --generate

소스파일 저장하기

1
2
3
4
5
git init
git remote add origin 소스파일을 저장할 저장소
git add .
git commit -m "메시지"
git push origin master

Reference

https://velog.io/@recordboy/%ED%97%A5%EC%86%8CHEXO%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EA%B9%83%ED%97%88%EB%B8%8C-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0