GTD

Getting Things Done (GTD) by David Allen - Animated Book Summary And Review
https://youtu.be/gCswMsONkwY

  • 위 영상에 대한 메모

GTD

  • 5 스텝으로 이뤄짐
  • capture -> process -> oranize -> review -> engage
  1. capture

    • 머릿속에 두지 말고 모든 생각을 다 적어라
  2. process

    • 담아둔 아이템들에 대해 질문해라

    • is it actionable? yes

    • can you do it in less than 2 minutes? yes/no

      • yes ; 바로 실행
      • no ; 액션 리스트에 추가
    • is it actionable? no

    • 2 choices ; discard / keep it as reference

    • 모든 항목에 대해 생각해라

  3. oganize

    • 마법이 일어난다

    • by project, time, context

    • 다음 항목에 대해 생각해라

    • 시퀀스를 잘 짜라

  4. review

    • 매주 리뷰해라
    • 모든 것을 원활하게 실행하려면 주간 검토가 필수적이다
    • 목표에 맞게 진행되고 있는지 반성해라
  5. engage

    • let’s get cracking! ; 즉시 일을 시작해라

참고

공유기가 2개일 때 포트포워딩

  • 통신사 공유기가 메인으로 있고,
  • 내 방 공유기가 있고, 컴퓨터에 연결된다
  • 위 상황일 때 특정 포트를 외부에서 접속할 수 있도록 포트포워딩해보자

최종 형태

  • 공유기 DMZ 설정하면 공유기 모든 포트가 개방된다
  • 내 방 공유기를 DMZ 설정하고, 메인 공유기에서만 포트포워딩하는 방향으로 설정해보겠다

내 방 공유기 DMZ 설정

  • 내 방 공유기에 접속하기 위해서 cmd를 열고 ipconfig를 입력한다
  • 이더넷 어댑터 이더넷에 기본 게이트웨이 주소로 접속한다
  • 각자 공유기 모델명과 DMZ 설정을 검색해 DMZ를 활성화하고 적용한다
  • 그러면 내 방 공유기로 3000번 포트 요청이 오면 내 컴퓨터 3000번 앱과 연결된다 (같은 포트로 1:1)
  • 이제 메인 공유기를 설정해보자

메인 공유기 포트포워딩

  • 메인 공유기에 접속을 어떻게 해야 할까?
  • 내 방 공유기 요약정보(보통 가장 첫 메뉴, 메인화면)에 보면 외부 ip를 확인할 수 있다
  • 외부 ip 주소로 접속하면 메인 공유기에 접속할 수 있다
  • 여기서 포트포워딩 설정을 해주면 된다

내 방 공유기 고정아이피 설정

  • 나는 내 방 공유기를 고정아이피로 설정해주었다

  • 포트포워딩할 때 특정 아이피에 대해 설정해줘야 한다

  • 내 방 공유기가 유동 아이피를 가진다면 제대로 동작하지 않을 것이다

  • 메인 공유기에서 특정 맥에 대해 고정 아이피 설정이 되지 않았다 (무슨 퍼미션 오류..)

  • 그래서 반대로, 내 방 공유기에서 자기 자신에 대해 고정아이피를 설정했다 (xxx.xxx.xxx.2)

  • DNS 서버, 보조 DNS 서버는 ipconfig 명령에서 찾아 적을 수 있다

  • 이제 메인 공유기 설정으로 돌아와서,

  • 위에서 설정한 고정아이피 주소가 다른 컴퓨터에 할당되어 충돌이 나면 안 된다

  • 메인 공유기에서 할당해주는 ip범위가 xxx.xxx.xxx.2를 포함하지 않도록 수정한다

포트포워딩 확인하기

  • 나는 간단하게 vscode로 live server 켰다
  • 내 아이피를 검색한다 (xxx.xxx.xxx.xxx)
  • 핸드폰으로 데이터를 켜서 접속해본다

keyword 카테고리 생성

  • 어떤 키워드에 대해 옆에 있는 사람한테 설명할 정도로 잘 알지는 못하지만 알고 있는 대로 적어보기
  • 잘 모르는 때, 해당 키워드에 대해 어떻게 설명할 수 있을까?
  • 글 작성 당시의 나는 해당 키워드를 어떻게 인식하고 있을까?
  • 흑역사 생성기
  • 어떤 지식에 대해 아주 잘 알고 있을 때, 하나도 모르는 사람에게 잘 알려줄 수 있을까?
  • 라는 물음으로 시작!

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>
  • 실제 포스트 영역에서 보이지 않게 했다

참고

First Contribution

  • 캬캬캬컄
  • 첫 번째? 기여
  • npm으로 다운받아지는 모듈에 내가…

tsc 문제

  • 타입스크립트로 프론트 프레임워크 없이 바닐라? 웹 프로젝트를 했다
  • vscode live server로 개발하고 있었다
  • import/export 구문을 사용하고 싶어서 tsconfig에서 module옵션을 commonjs가 아닌 es2020으로 사용했다
  • 그런데 한 가지 문제가 있었다
  • 아래 tsc의 결과로 트랜스파일 된 js들이 있다
main.ts
1
import tmp from './tmp';
main.js
1
2
3
import tmp from './tmp'; // tsc 결과

import tmp from './tmp.js'; // 내 기대값
  • tsc 이후에 확장자가 달리지 않는 문제?가 있었다
  • 이러면 live server는 localhost:5500/js/tmp를 못 찾는다
  • localhost:5500/js/tmp.js 확장자까지 모두 있어야 파일을 찾아 로드할 수 있었다
  • 이거에 대해 구글링을 해보니까
  • .ts 파일에서 작업할 때 .js 확장자를 붙이는 방법이 있었다
1
2
3
4
5
6
7
// src-ts/tmp.ts
const tmp = 'chinsung';
export default tmp;

// src-ts/main.ts
import tmp from './tmp.js';
console.log(tmp);
  • 근데 이건 에디터에서는 잘 알아듣게 할 수 있지만
  • 코드를 봐서도 아름답지 못한 느낌이 팍 들었다
  • 다른 방법으로는 서버에서 파일을 찾을 때
  • 확장자가 생략이 되어도 그에 맞는 파일을 서빙하도록 설정하는 방법이 있었다
  • 먼저 live server에서 라우터나 서빙 관련 뭔가 설정 가능한 게 있는지 살펴봤는데 없었다
  • express 서버를 만들고 해당 기능을 추가하기에는 auto refresh 기능을 포기하고 싶지 않았다

tsc-es2020-fix 발견

tsc-es2020-fix 문제 발견

  • 잘 쓰고 있다가 한 가지 문제점을 발견했다
main.ts
1
2
3
import tmp from './tmp';
// ->
import tmp from './tmp.js';
  • 같은 레벨의 파일 참조는 잘 변환이 되는데
main.ts
1
2
3
import tmp from '../tmp';
// ->
import tmp from '../tmp'; // 확장자가 붙지 않는다..!
  • 상위 디렉터리를 거치는 경우에 기대한 대로 동작하지 않았다
  • node_modules에서 tsc-es2020-fix를 이리저리 둘러보다가
  • 변환이 이뤄지는 로직을 찾았다
fix.js
1
2
3
4
5
contents.replace(
/(\sfrom |\simport\()(["'])(\.\/[^"']+)(["'])/g,
(matched, control, q1, from, q2) =>
`${control}${q1}${resolveDependency(filename, from, filenames)}${q2}`
);
  • 정규식으로 import / export 구문을 찾고 확장자를 붙여주는 것이었다
  • 나는 여기서 정규식을 수정하면 될 것 같았다

  • 간단하게 위 경우도 찾을 수 있게 수정했다
fix.js
1
2
3
4
5
contents.replace(
/(\sfrom |\simport\()(["'])(\.{0,2}\/{0,1}[^"']+)(["'])/g,
(matched, control, q1, from, q2) =>
`${control}${q1}${resolveDependency(filename, from, filenames)}${q2}`
);
  • 그러자 내가 기대하는 대로 동작하기 시작했다
  • 이때 너무 기분이 좋아서 원본 레포에 가서 fork하고 자신감 넘치게 PR를 했다

첫 기여

  • PR을 보내고 얼마 지나지 않아 답변이 왔다
  • 테스트를 추가해 달라였는데, 나는 엄청 당황했다 ㅋㅋㅋ
  • 테스트 케이스인 파일을 추가하고 jest -u를 돌려달라는데
  • jest부터 몰라서 jest 공부도 하고..
  • 프로젝트 구조도 잘 모르는데, 어찌어찌 내가 생각하는 대로 파일 추가하고 테스트 한 다음에
  • 내 PR을 적용하기 전과 후 결과를 스샷 찍어서 답글을 달았다

  • 괜찮아 보인다며 내 PR이 병합됐다!!
  • 내 변경사항으로 모듈이 업데이트되고, 뭔가 기분이 좋았다

후기

  • 처음 모르는 레포에 가서 PR을 했다
  • PR하고 피드백받고, 테스트 코드 추가하면서 엄청 떨렸다
  • 그러면서 기여를 어떻게 해야하는지 찾아보고
  • https://github.com/sindresorhus/.github/blob/main/contributing.md
  • 엄청난 오픈소스 개발자 깃허브도 찾고,,
  • 기여를 어떻게 해야 하는지에 대한 문서에
  • fork 한 다음에 master 브랜치 작업하고 PR를 보내지 마라라는 항목이 있어서 부끄러워졌다..

참고

블로그 댓글 시스템 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로 수정했다

slash converter

  • 파일 경로 문자열 변환기를 만들었다
  • 파일 경로를 적어야 할 때가 생각보다 많은데
  • 어떤 때는 /를 사용하고
  • 어떤 때는 \를 사용하고
  • 또 어떤 때는 \\를 사용한다
  • 일일이 수정해주기 귀찮을 때가 분명히 있었을 것이다

변환 코드

Main.tsx
1
2
3
const convertSlash = (type: string, origin: string) => {
return origin.replace(/[/\\]+/g, type);
};
  • 슬래시와 백슬래시를 찾아내서 정해진 타입으로 변환한다

그 외

  • emotion theme provider를 사용해 테마를 적용해보았다

참고

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이 생성될 것이다

후기

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