blog update - 다크 테마용 favicon

  • 테마를 전환할 때 favicon url도 업데이트한다
  • 2개의 favicon 파일이 있다
theme.js:44
1
2
3
4
5
6
function setFaviconTheme(theme) {
const href = `https://cdn.jsdelivr.net/gh/chinsun9/chinsun9.github.io@master/img/favicon-bold-color210928${
theme === 'dark' ? '-dark' : ''
}.svg?`;
document.querySelector(`head > link[rel="icon"]`).href = href;
}

메모

  • favicon으로 쓰이는 svg에 어떻게 색을 넘길까..?
  • 그냥 svg 2개 만들어서 토글하기
  • 기존 테마 파일 리팩토링

참고

blog fix 다크 모드 화면 깜박임 제거

화면을 넘어갈 때 눈뽕(기본 테마가 잠깐 렌더링 됨)을 해결하기

상황

  • 다크 모드에서 계속 새로고침하고 있는 상황이다
  • 중간에 번쩍하고 흰색이 보였다
  • 다크 모드 사용 중에 이렇게 새로고침이나 페이지가 넘어갈 때마다 종종 흰색 화면으로 뒤덮이는 문제가 있었다
  • 디폴트 테마 ; 화이트
  • 설정한 테마 ; 다크
  • 다크 모드이면 body에 dark 클래스 추가
  • 다크 모드에서 새로고침이나 화면을 넘어갈 때 잠깐 흰색 화면이 보인다
  • 해결해보자

해결

  • body 태그 바로 아래에 스크립트를 두어 렌더링을 막았다
  • html에 백그라운드 css가 있다면 삭제

알아낸 점

  • 페이지가 넘어갈 때 이전 화면의 백그라운드가 유지된다 (이전 화면의 html이나 body의 백그라운드 컬러)
  • 렌더링은 완전히 파싱이 끝난 후에 이뤄진다
  • 중간에 스크립트를 두어 렌더링을 막을 수 있다(블로킹)
  • color-scheme css를 사용하면 스크롤바 다크 모드도 적용할 수 있다
  • color-scheme css를 사용하면 기본 백그라운드가 생긴다 (dark일시 어두운 백그라운드)

다크 모드 체크리스트

  • color-scheme css 사용하기
  • html 또는 body 태그에 적용되는 백그라운드 색이 있다면 없애기
  • 테마 초기화하는 블로킹 스크립트 넣기

참고

blog fix 카피 버튼이 안나오는 문제

  • 블로그에 코드 스니펫 오른쪽 위에 카피 버튼이 나올 때도 있고 안 나올 때도 있었다
  • 무한 새로고침하면 종종 모습을 비춘다… (이스터에그도 아닌 것이..)

환경

  • hexo-theme-icarus v4.0.1

해결하기

  • 일단 어디서 이 버튼을 생성하는지 알아내야 한다
  • 버튼이 정상적으로 출력되었을 때 해당 버튼의 클래스명을 확인했다
  • 그리고 main.js라는 곳에서 동적으로 버튼을 생성하고 있음을 알아냈다
themes\icarus\source\js\main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
console.log(clipboard, typeof ClipboardJS);
if (typeof ClipboardJS !== 'undefined' && clipboard) {
$('figure.highlight').each(function () {
const id = 'code-' + Date.now() + ((Math.random() * 1000) | 0);
const button =
'<a href="javascript:;" class="copy" title="Copy" data-clipboard-target="#' +
id +
' .code"><i class="fas fa-copy"></i></a>';
$(this).attr('id', id);
$(this).find('figcaption div.level-right').append(button);
});
new ClipboardJS('.highlight .copy'); // eslint-disable-line no-new
}
  • 조건문에 ClipboardJS가 있으면 버튼을 생성하는데
  • main.js에는 ClipboardJS에 대해 따로 선언이 없었고, 외부 라이브러리라는 것을 알았다
  • 이 ClipboardJS가 어디서 오는지 확인해야 했다
themes\icarus\layout\common\scripts.jsx
1
2
3
4
5
6
7
8
9
{
clipboard && (
<script
src={cdn('clipboard', '2.0.4', 'dist/clipboard.min.js')}
// async
defer
></script>
);
}
  • layout\common\scripts.jsx에서 가져오는 코드를 확인했는데
  • async으로 가져오고 있었다
  • 문제는 clipboardJS가 로드되기 전에 main.js가 먼저 실행되는 문제였다
  • defer로 수정하니까 잘 동작했다!

최신 버전 확인

  • hexo-theme-icarus v4.2.0
  • 최신 버전을 확인하니까 defer로 변경되어있었다… (이슈 검색했을 때는 못 찼았다…)
  • 처음부터 최신 버전을 참고하면 좋았겠다
  • 9개월 정도 나름대로 커스텀하면서 사용해왔는데,
  • 나중에 시간 나면 커스텀한 내용을 유지하면서 최신 버전에 맞게 업데이트해줘야겠다

참고

async, defer

blog update 404

after

before

  • 기존에는 iframe으로 배너메이커를 보여줬다
  • hexo 프론트 메터를 layout: false로 설정해 내가 원하는 대로 커스텀할 수 있었다
  • 당시에는 404 페이지에 넣을 내용도 없고 당시 만들었던 배너메이커를 자랑하고자 했다
  • 근데 블로그와 404페이지는 아무 관계가 없는 것처럼 느껴졌다
  • 그래서 이번엔 layout: true 레이아웃을 하면서 간단한 css 이펙트를 넣어보자 생각했다

typewriter animation

hexo front-matter

  • 내 환경은 다음과 같다

    • hexo: 5.4.0
    • hexo-cli: 4.2.0
404.html
1
2
3
4
5
6
7
---
title: 404
widgets: null
comment: false
article:
- license: false
---
  • 404 화면에 위젯, 코멘트, 라인센스 영역을 없애기 위해 설정했다
  • title은 넣어주면 head의 title tag에 반영되어서 넣어줬다
404.html
1
2
3
4
5
<style>
h1.title {
display: none;
}
</style>
  • 실제 포스트 영역에서 보이지 않게 했다

참고

블로그 댓글 시스템 disqus에서 utterances로 바꾸기

  • disqus에 달린 댓글을 utterances가 읽을 수 있게 이슈 생성하기
  • 자문자답하는 것처럼 하나의 계정으로 달리지만 댓글이 없어지지 않는 게 의미가 크다..!

  • 이런 형식이 utterances가 사용하는 포맷이다
  • 이 포맷과 동일하게 수동으로 이슈를 등록하는 것도 좋은? 방법이다

하는 법

환경

  • windows 10
  • 나는 hexo, icarus theme를 사용하고 있다
  • hexo version ; 5.0.0
  • hexo-theme-icarus version ; 4.0.1

disqus 기존 댓글 가져오기

  • 블로그에 댓글 몇 개 없지만 없는 만큼 너무 소중해서 같이 옮긴다

https://lazywinadmin.com/2019/04/moving_blog_comments.html

  • 위 글을 따라가면서 블로그 댓글 시스템 disqus에서 utterances로 바꿔보자
  • 위 글에서는 파워셸을 통해서 export 한 xml을 조작해서 utterances에서 사용하는 이슈로 등록해준다

  • disqus에 로그인한 상태로
  • https://chinsung.disqus.com/admin/discussions/export/
  • 위 링크로 접속해서 버튼을 누르면 된다
  • 버튼을 누르면 내 요청이 큐가 되었다고 하면서 결과를 이메일로 보내준다고 한다
  • 나 같은 경우 바로 이메일이 왔다

  • 링크를 눌러 다운로드하자
  • 압축을 풀면 xml 파일이 나온다
  • 앞으로의 내용은 이 xml 파일을 읽어서 작업한다

disqus 댓글 정제하기

  • 참고로 나는 파워셸 커맨드를 잘 모른다
  • 그대로 따라 하다가 내가 겪었던 문제들이 몇 가지 있었다
  • 원본 글에서는 커맨드에 대해 블록을 나눠서 잘 설명해준다
  • 나는 설명보다는 내가 어떤 문제를 만나서 코드를 어떻게 수정했고
  • 성공한 코드를 마지막에 통짜로 첨부하겠다
  • 파워셸을 관리자 권한으로 실행한다
  • 편한 작업을 위해 cd 명령으로 xml이 있는 위치로 이동한다
  • 나는 파워셸 스크립트(foo.ps1)를 만들어서 실행하는 방법으로 했다
  • 실행은 .\myPsScript.ps1 이렇게 앞에 .\을 붙여 실행할 수 있다

파워셸 시크립트 실행 활성화

  • 파워셸 스크립트를 실행하려면 실행 정책을 변경해야 한다
1
2
Set-ExecutionPolicy AllSigned
Set-ExecutionPolicy RemoteSigned
  • 변경하시겠습니까? 물어보면 Y로 답하면 된다

인코딩 문제

  • 파일을 읽는 것부터 실패했다
new1.ps1
1
2
3
4
5
6
7
8
9
# Load the file
# $Disqus = Get-Content -Path .\origin.xml
$Disqus = Get-Content -Path .\origin.xml -encoding UTF8 # 여기 -encoding UTF8 추가

# Cast the file to XML format
$DisqusXML = ([xml]$Disqus).disqus

# Output result
$DisqusXML
  • -encoding UTF8을 추가해준다

필터링 문제

1
2
3
4
5
6
7
8
9
10
$AllThreads = $AllThreads |
Where-Object -FilterScript {
$_.link -match "
\.io\/\d{4}\/.+html$|
\.com\/\d{4}\/.+html$|
\.com\/p\/.+html$|
\.io\/minimal-mistakes\/\d{4}\/.+html$|
\.io\/powershell\/\d{4}\/.+html$|
\.io\/usergroup\/\d{4}\/.+html$" -and
$_.link -notmatch "googleusercontent\.com"}
  • 문제까지는 아니고, 글을 잘 안 읽고 그냥 코드를 복붙하다 보니까
  • 글쓴이에 상황에 맞춰진 조건을 그대로 사용해 생긴 문제였다
  • 저 코드를 내 상황에서 돌리면 모든 쓰레드가 조건에 충족하지 않아 결과가 빈 배열이다
  • 나는 필터링이 필요하지 않았다 그래서 이 과정은 생략했다

개인 설정 문제

1
2
3
4
5
6
# Define Github commands default params
$GithubSplat = @{
OwnerName = 'lazywinadmin'
RepositoryName = 'lazywinadmin.github.io'
}
$BlogUrl = 'https://lazywinadmin.com'
  • 코드 좀 보고 복붙하자…
  • 남의 레포를 업데이트할 권한이 없어서 망정이지…
1
2
3
4
5
6
# Define Github commands default params
$GithubSplat = @{
OwnerName = 'chinsun9'
RepositoryName = 'chinsun9.github.io'
}
$BlogUrl = 'https://chinsun9.github.io/' # 주의! 마지막 슬래시 넣기!
  • 내 환경에 맞게 적절히 수정해준다

github personal access token 발급 받기

  • 파워셸에서 github api를 통해 이슈를 자동 생성한다
  • github api를 사용하기 위해서는 토큰이 필요하다
  • github에 로그인한 상태로
  • https://github.com/settings/tokens
  • 에 접속해서 Generate new token 버튼을 누른다

  • note를 적당히 작성하고
  • repo 전체 권한을 가지도록 생성한다
  • 생성된 키를 복사한다

완성 코드

  • 내가 사용한 코드이다
  • 실행할 때는 관리자 권한으로 파워셸을 실행시켜야 한다
  • 가장 상위에 개인이 설정해야 하는 변수들을 몰아놨다
  • 해당 변수들은 전부 자신에 맞게 수정한 다음 실행해보아야 한다
  • 특히 RepositoryName은 일회용으로 사용할 레포를 생성하고 한번 테스트해보는 것을 추천한다
  • 혹시나 잘못된 이슈가 엄청나게 생성될 수 있기 때문이다
  • 일회용 레포를 하나 만들고 테스트해보고 진짜 레포에 적용하는 게 좋을 것 같다
  • 파워셸에서 github api를 사용하기 위한 powershellforgithub 모듈을 다운로드하는 코드가 4번째 라인에 있다
  • 코드를 실행하면 뭐라 뭐라 설치할 건지 물어보는데 모두 Y로 답하면 된다
  • utterances는 공개 레포에서 작동하니까 별도 레포를 만들지 않고,
  • 블로그의 본체인 chinsun9.github.io 레포를 그냥 사용했다
complete code
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# 출처 ; https://lazywinadmin.com/2019/04/moving_blog_comments.html

# First fetch the module from the PowerShell Gallery
Install-Module -Name powershellforgithub -scope currentuser -verbose
# Import it
Import-Module -Name powershellforgithub

### 개인 설정 시작 ###
$filePath = '.\origin.xml' # disqus export xml filepath

# Define Github commands default params
$GithubSplat = @{
OwnerName = 'chinsun9' # github username
RepositoryName = 'chinsun9.github.io' # reponame ; 처음 테스트할 땐 일회용 레포하나 만들고 결과가 어떻게 나오나 확인해자
}
$BlogUrl = 'https://chinsun9.github.io/' # blog url ; 마지막 슬래시 있어야함!

# Specify our Github Token
$key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' # 깃허브에서 발급한 personal access token!!

$IssueLabel = 'blog comments' # 라벨 설정
### 개인 설정 끝 ###

# Load the file
$Disqus = Get-Content -Path $filePath -encoding UTF8

# Cast the file to XML format
$DisqusXML = ([xml]$Disqus).disqus


# 코멘트 작업
# Retrieve all Comments
$AllComments = $DisqusXML.post

# Retrieve properties available for each comments
$Properties = $AllComments | Get-Member -MemberType Property

# Process each Comments
$AllComments = $AllComments | Foreach-Object -process {

# Store the current comment
$Comment = $_

# Create Hashtable to store properties of the current comment
$Post = @{}

# Go through each properties of each comments
foreach ($prop in $Properties.name) {
if ($prop -eq 'id') {
# Capture Unique IDs
$Post.DsqID = $Comment.id[0]
$Post.ID = $Comment.id[1]
}
elseif ($prop -eq 'author') {
# Author information
$Post.AuthorName = $Comment.author.name
$Post.AuthorIsAnonymous = $Comment.author.isanonymous
}
elseif ($prop -eq 'thread') {
# Here is the important data about the
# thread the comment belong to
$Post.ThreadId = $Comment.thread.id
}
elseif ($prop -eq 'message') {
$Post.Message = $Comment.message.'#cdata-section'
}
else {
# Other properties
$Post.$prop = ($Comment |
Select-Object -ExpandProperty $prop ) -replace '`r`n'
}
# Keep the original comment data structure if we need it later
$Post.raw = $Comment
}
# Return a PowerShell object for the current comment
New-Object -TypeName PSObject -Property $Post
}

# 쓰레드 작업
# Retrieve threads
$AllThreads = $DisqusXML.thread

# Retrieve Thread properties
$Properties = $AllThreads | Get-Member -MemberType Property

# Process each threads
$AllThreads = $AllThreads | Foreach-Object -process {

# Capture Current ThreadItem
$ThreadItem = $_

# Create Hashtable for our final object
$ThreadObj = @{}

# Go through each properties of each threads
foreach ($prop in $Properties.name) {
if ($prop -eq 'id') {
# Thread ID
$ThreadObj.ID = $ThreadItem.id[0]
}
elseif ($prop -eq 'author') {
# Author
$ThreadObj.AuthorName = $ThreadItem.author.name
$ThreadObj.AuthorIsAnonymous = $ThreadItem.author.isanonymous
$ThreadObj.AuthorUsername = $ThreadItem.author.username
}
elseif ($prop -eq 'message') {
$ThreadObj.Message = $ThreadItem.message.'#cdata-section'
}
elseif ($prop -eq 'category') {
$ThreadObj.Category = ($ThreadItem |
Select-Object -ExpandProperty $prop).id
}
else {
# Other properties
$ThreadObj.$prop = ($ThreadItem |
Select-Object -ExpandProperty $prop) -replace '`r`n'
}
$ThreadObj.raw = $ThreadItem
}
# Return a PowerShell object for the current ThreadItem
New-Object -TypeName PSObject -Property $ThreadObj
}

$AllThreads = $AllThreads |
Select-Object -Property *,
@{L = 'link2'; E = {
$_.link -replace "$($BlogUrl)" }
},
@{L = 'title2'; E = {
$_.title }
} |
Group-Object -Property link2


$ThreadsUpdated = $AllThreads |
Sort-Object -Property count |
ForEach-Object -Process {

# Capture current post
$CurrentPost = $_

# if one comment is found
if ($CurrentPost.count -eq 1) {
if ($CurrentPost.group.title2 -notmatch '^http') {
# Add REALTitle property
$RealTitle = $CurrentPost.group.title2
# output object
$CurrentPost.group |
Select-Object -Property *,
@{L = 'RealTitle'; e = { $RealTitle } },
@{L = 'ThreadCount'; e = { $CurrentPost.count } }
}
elseif ($CurrentPost.group.title2 -match '^http') {
# lookup online
$result = Invoke-webrequest -Uri $CurrentPost.group.link -Method Get
# add REALTitle prop
$RealTitle = $result.ParsedHtml.title
# output object
$CurrentPost.group |
Select-Object -Property *,
@{L = 'RealTitle'; e = { $RealTitle } },
@{L = 'ThreadCount'; e = { $CurrentPost.count } }
}
}
if ($CurrentPost.count -gt 1) {
if ($CurrentPost.group.title2 -notmatch '^http') {
# add REALTitle prop
$RealTitle = ($CurrentPost.group.title2 |
Where-Object -FilterScript {
$_ -notmatch '^http' } |
Select-Object -first 1)

# Output object
$CurrentPost.group |
Select-Object -Property *,
@{L = 'RealTitle'; e = { $RealTitle } },
@{L = 'ThreadCount'; e = { $CurrentPost.count }
}
}
elseif ($CurrentPost.group.title2 -match '^http') {
# get url of one
$u = ($CurrentPost.group |
Where-Object {
$_.title2 -match '^http' } |
Select-Object -first 1).link

# lookup online
$result = Invoke-webrequest -Uri $u -Method Get

# add REALTitle prop
$RealTitle = $result.ParsedHtml.title
# output object
$CurrentPost.group |
Select-Object *, @{L = 'RealTitle'; e = { $RealTitle }
}
}
else {
# add REALTitle prop
$RealTitle = 'unknown'
# output object
$CurrentPost.group | Select-Object *, @{L = 'RealTitle'; e = { $RealTitle } }
}
}
}


$AllTogether = $AllComments | ForEach-Object -Process {

$CommentItem = $_


$ThreadInformation = $ThreadsUpdated |
Where-Object -FilterScript {
$_.id -match $CommentItem.ThreadId
}

$CommentItem |
Select-Object -Property *,
@{L = 'ThreadTitle'; E = { $ThreadInformation.Realtitle } },
@{L = 'ThreadLink'; E = { $ThreadInformation.link2 } }
} |
Group-Object -Property ThreadLink |
Where-Object -FilterScript { $_.name }


# 이슈달기 작업
$KeySec = ConvertTo-SecureString $key -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ('username_is_ignored', $KeySec)
#$cred = Get-Credential -UserName $null

# Set Connection and configuration
Set-GitHubAuthentication -Credential $cred
Set-GitHubConfiguration -DisableLogging -DisableTelemetry


# Retrieve issues
#$issues = Get-GitHubIssue -Uri 'https://github.com/lazywinadmin/lazywinadmin.github.io'
$issues = Get-GitHubIssue @githubsplat

# Process each threads with their comments
$AllTogether |
Sort-Object name -Descending |
ForEach-Object -Process {

# Capture current thread
$BlogPost = $_

# Issue Title, replace the first / and
# remove the html at the end of the name
$IssueTitle = $BlogPost.group.ThreadLink |
select-object -first 1

# lookup for existing issue
$IssueObject = $issues |
Where-Object -filterscript { $_.title -eq $IssueTitle }

if (-not $IssueObject) {
# Build Header of the post
$IssueHeader = $BlogPost.group.ThreadTitle |
select-object -first 1

# Define blog post link
$BlogPostLink = "$($BlogUrl)$($BlogPost.name)"

# Define body of the issue
$Body = @"
# $IssueHeader

[$BlogPostLink]($BlogPostLink)

<!--
Imported via PowerShell on $(Get-Date -Format o)
-->
"@
# Create an issue
$IssueObject = New-GitHubIssue @githubsplat `
-Title $IssueTitle `
-Body $body `
-Label $IssueLabel
}

# Sort comment by createdAt
$BlogPost.group |
Where-Object { $_.isspam -like '*false*' } |
Sort-Object createdAt |
ForEach-Object {

# Current comment
$CurrenComment = $_

# Author update
# we replace my post author name :)
$AuthorName = $($CurrenComment.AuthorName)
switch ($AuthorName) {
'Xavier C' { $AuthorName = 'Francois-Xavier Cat' }
default {}
}

# Define body of the comment
$CommentBody = @"

## **Author**: $AuthorName
**Posted on**: ``$($CurrenComment.createdAt)``
$($CurrenComment.message)

<!--
Imported via PowerShell on $(Get-Date -Format o)
Json_original_message:
$($CurrenComment|Select-Object -ExcludeProperty raw|convertTo-Json)
-->
"@
# Create Comment
New-GitHubComment @githubsplat `
-Issue $IssueObject.number `
-Body $CommentBody
}
# Close issue
Update-GitHubIssue @githubsplat `
-Issue $IssueObject.number `
-State Closed
}

utterances 설정하기

  • 난 특정 레포에만 설치했다
  • 여기 설정은 언제든지 수정 가능하다
  • 놀랍게도 끝났다
  • 내가 사용하는 icarus 테마는 댓글로 discus, utterances 등 여러 타입의 플러그인을 지원해서 config에 추가하면 적용 완료다

blog config 설정하기

_config.icarus.yml
1
2
3
4
5
6
7
comment:
type: utterances
repo: chinsun9/chinsun9.github.io
issue_term: pathname
label: blog comments
theme: github-light
crossorigin: anonymous
  • 위처럼 설정한다
  • 레포는 퍼블릭 레포여야 한다
  • 내가 사용한 방법을 그대로 따라왔다면 issue_term은 pathname을 사용해야 한다
  • label도 등록된 이슈와 동일하게 설정한다

utterances css 수정하기 ; width 100%

default.styl
1
2
3
.utterances {
max-width: none;
}
  • 각자 테마 디렉터리로 가서 css 파일에 가서 추가한다

주의사항

테마 설정 시

  • hexo icarus config에서 utterances 테마를 설정할 때
  • preferred-color-scheme는 지원하지 않는 것 같다…
  • 이 값이 올 수 없다며 스키마 오류가 난다 (버전 문제일 수 있음)
  • github-dark, github-light은 가능하다

이슈 제목

  • utterances에서 이슈와 포스트를 맵핑할 때 여러 옵션이 있다
  • 맘에 드는 걸로 골르면 된다 (이 글을 그대로 따라왔다면 pathname으로 해야 함!)
  • 블로그 포스트를 작성하고 수정될 가능성이 있는 값으로 지정하지 않은 게 좋다
  • 나는 첫 번째 옵션인 Issue title contains page pathname으로 매핑하기로 했다
  • 참고로 내 블로그 pathname은 /YYYY/MM/DD/post-title 로 구성되어 유니크한 이름을 가질 수 있다
  • 포스트의 pathname에 한글이 들어가면 이상한 인코딩 된 이슈 제목을 가진다
  • 앞으로 pathname에 한글이 들어가지 않도록 글을 써야겠다…

  • 이렇게 되기 싫으면…

바꾼 이유

  • disqus를 사용하면 링크가 넣을 수 없다?
  • 댓글에 포함되어 있는 링크가 disqus를 통해 리디렉트되도록
  • https://disq.us/url?url=https%3A%2F%2Fchinsun9.github.io%2F2020%2F11%2F18%2Freact-typescirpt...
  • 이렇게 감싸 진다
  • 근데 문제는 이렇게 감싸진 링크를 클릭하면 연결이 안 된다
  • 내가 무슨 설정을 잘못한 건지 모르겠지만…
  • 또, 나는 disqus를 블로그를 하기 전까지 모르고 있었다
  • 댓글을 달기 위해서 disqus를 가입해야 하는 벽?이 있지 않을까 생각하게 되었다

참고

blog update utterances

  • 댓글 시스템을 disqus에서 utterances로 수정했다

blog update dark theme

  • 캬캬캬
  • 블로그 dark 테마 적용
  • 상단 오른쪽 검색 버튼 옆에서 토글 할 수 있다!!

다크 테마를 적용한 이유

  • github 프로필 메인에 dark theme를 토글하는 버튼이 있었는데
  • 어느샌가 세팅 하위 메뉴로 들어가야 변경이 가능했다
  • 세팅에서 테마를 고르는데 시스템 테마를 상속받아 보여주는 옵션이 있었다
  • 궁금해서 공부해보고 블로그에도 적용하게 되었다
  • 처음 C언어를 배울 때 visual studio 사용했다
  • 기본 테마가 화이트였다
  • 기본 테마를 쓰다가 웹 공부를 시작하면서 유튜버들 세팅을 따라 하다가 다크 테마를 쓰게 됐다
  • 써보니까 괜찮고 좋은 것 같다!

환경

  • 나는 icarus default theme를 사용 중이다

적용 방법

  • 기본적으로 body에 dark class 가 있으면 다크 테마에 맞는 css로 오버라이드하는 방식이다

css 추가

  • dark theme에 맞게 새로 추가할 css는

  • icarus theme 디렉터리를 기준으로 source/css 아래에 dark.styl이름으로 파일을 하나 생성했다
  • 앞으로 나오는 경로는 모두 icarus theme 디렉터리가 기준이다
source/css/dark.styl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
body.dark {
background-color: #1e1e1e;

.navbar {
background-color: #3C3C3C;
color: #d4d4d4;

.navbar-menu {
background-color: transparent !important;

.navbar-item {
color: inherit;

&:hover, &:focus {
background-color: #37373D;
color: #007acc;
}
  • 어떤 테마 시스템이 있고 그런 게 아니라서 하나하나 수작업으로 바꿔주었다
  • body.dark 일 때 css를 오버라이드 할 수 있도록…
source/css/style.styl
1
2
// ...
@import './dark.styl';
  • dark.stylstyle.styl 마지막에 임포트 해준다
  • 그럼 css는 끝!

토글 버튼 추가

  • 이제 토글 버튼을 추가해보자
  • 나는 navbar 상단 오른쪽 검색 버튼 옆에 추가했다
layout/common/navbar.jsx
1
2
3
4
<div class="navbar-end">
<button type="button" id="toggleTheme" class="navbar-item">
hi
</button>
  • layout/common/navbar.jsx 80라인에 toggleTheme라는 ID로 추가했다
  • 이제 버튼에 기능을 넣어줘야 하는데 navbar.jsx에서 기능도 추가하고 싶었는데,
  • 어떻게 빌드되는지 구조를 잘 몰라서 실패했다

  • 대신 source/js 디렉터리에 theme.js 파일을 하나 추가했다
theme.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
42
43
44
45
46
47
48
49
50
51
52
53
const btn = document.getElementById('toggleTheme');

function initTheme() {
// chk local storage
const theme = localStorage.getItem('theme');
if (theme === 'dark') {
document.body.classList.add('dark');
btn.innerText = '🌙';
return;
}
if (theme === 'light') {
btn.innerText = '🌞';
return;
}

// visit first time
const isDark = window.matchMedia('(prefers-color-scheme: dark)');
if (isDark) document.body.classList.add('dark');

localStorage.setItem('theme', isDark ? 'dark' : 'light');
btn.innerText = isDark ? '🌙' : '🌞';
}

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

window
.matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', (e) => {
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 = '🌞';
});

btn.addEventListener('click', function (event) {
toggleTheme();
});

initTheme();
  • 셀럭터로 위에서 추가한 버튼을 가져와서 클릭 이벤트 리스너를 달아줬다
  • 이제 hexo로 빌드하면서 생성되는 html에 해당 스크립트를 로드하도록 해야 한다

스크립트 파일 추가

  • layout/common/scripts.jsx에 위에서 만든 theme.js를 등록하면 된다
layout/common/scripts.jsx
1
2
3
4
5
<Fragment>
// ...
<script src={url_for('/js/main.js')} defer></script>
<script src={url_for('/js/theme.js')} defer></script>
</Fragment>
  • 56라인 정도 되는 부분에 <script src={url_for('/js/theme.js')} defer></script> 추가한다
  • 마지막으로 hexo 디렉터리로 돌아와서 public/css 하위에 있는 css를 삭제해준다
  • 이제 hexo generate 하게 되면 css가 갱신되고, 테마 토글 버튼이 달려 있는 html이 생성될 것이다

후기

  • 뿌듯하다
  • 다 완성하고 자려고 누워서 폰으로 내 블로그를 들어가 봤는데 눈이 편안했다

깃허브 블로그 느린 웹 해결하기

  • 2020.01.04 처음 느린 웹 보고서를 확인하고 그냥 방치 했는데…
  • 나날이 늘어가는 느린 URL들…

  • jsdelivr 적용 후, 지금까지!

상황

  • 구글 서치 콘솔에서 블로그에 대한 보고서를 보는데, 느린 웹 문제가 있었다
  • 어떻게 블로그를 빠르게 할 수 있는지 고민해보았다

내 환경

  • hexo 프레임워크로 블로그를 운영하고 있다
  • 블로그 글이 점점 많아지고, 글에 많은 이미지를 포함하는 글도 있다

해결 : jsdelivr 적용

  • jsdelivr는 npm과 github에서 사용할 수 있는 무료 CDN이다
  • 오픈소스 프로젝트를 위한 CDN이라고 한다
  • jsdelivr는 아무런 설정 없이 누구나(npm, github 사용자) 사용할 수 있는 게 장점이다

jsdelivr 사용법

https://chinsun9.github.io/images/web-dark-theme20210531/preview.png (원본)
https://cdn.jsdelivr.net/gh/chinsun9/chinsun9.github.io@master/images/web-dark-theme20210531/preview.png (CDN 적용)

hexo에서 적용

  • 포스트를 작성할 때 cdn을 적용한 url을 적어줘도 상관은 없지만,
  • 이미 작성된 글들에 대해 수행해야 하는 불편함이 있다
  • hexo 모듈을 살펴보니 node_modules/hexo/lib/plugins/filter/after_post_render/index.js에서 추가적인 작업을 해줄 수 있다는 것을 알게 되었다
hexo/lib/plugins/filter/after_post_render/index.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
'use strict';

module.exports = (ctx) => {
const { filter } = ctx.extend;

function lazyProcess(htmlContent) {
let rootUrl =
'https://cdn.jsdelivr.net/gh/chinsun9/chinsun9.github.io@master';
return htmlContent.replace(
/<img(.*?)src="(.*?)"(.*?)>/gi,
function (str, p1, p2) {
if (/src="data:image(.*?)/gi.test(str)) {
return str;
}
if (p2.indexOf('http') === 0) {
return str;
}
return str.replace(p2, rootUrl + p2);
}
);
}

filter.register('after_post_render', require('./external_link'));
filter.register('after_post_render', require('./excerpt'));
filter.register('after_post_render', function (data) {
data.content = lazyProcess.call(this, data.content);
return data;
});
};
  • node_modules 아래에 있는 파일을 수정한 것이라, 좋은 접근은 아닌 것 같다
  • 이런 경우에 어떻게 노드 모듈 외부에서 함수를 오버라이딩할 수 있는지…
  • 일단 나는 이렇게 해서 사용하고 있다

경과

  • 2021-03-12 이미지에 cdn 적용했다

  • 10일 후에 점점 느린 URL이 없어지고 있는 것을 확인할 수 있다

  • 지금은 느린 웹이 없다!

주의사항

  • 이미지를 수정해도 즉시 반영되지 않는다
  • 즉시 반영을 원한다면 이름을 바꿔주자

참고

블로그 테마 업데이트

  • 배경색을 흰색으로 바꾸고, 깔끔하게 바꿔보았다