for-humanity 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/LICENSE +1 -1
- package/README.md +3 -3
- package/dist/browser.js +9 -9
- package/dist/cli.css +39 -322
- package/dist/cli.js +123 -309
- package/package.json +4 -3
- package/src/asset/font/ibm-plex-sans-kr/IBMPlexSansKR-Regular.woff2 +0 -0
- package/src/asset/font/ibm-plex-sans-kr/IBMPlexSansKR-SemiBold.woff2 +0 -0
- package/src/asset/font/{pretendard → ibm-plex-sans-kr}/LICENSE.txt +4 -5
- package/src/asset/font/ibm-plex-sans-kr/ibm-plex-sans-kr.css +22 -0
- package/src/asset/font/{jetbrains-mono/LICENSE → monoplex-kr/LICENSE.md} +61 -8
- package/src/asset/font/monoplex-kr/MonoplexKR-Regular.woff2 +0 -0
- package/src/asset/font/monoplex-kr/MonoplexKR-SemiBold.woff2 +0 -0
- package/src/asset/font/monoplex-kr/monoplex-kr.css +20 -0
- package/src/component/widget/navigation/_constant/navigation-data-schema.ts +0 -3
- package/src/component/widget/navigation/_constant/navigation.ts +2 -2
- package/src/component/widget/navigation/_function/to-navigation-data/_to-navigation-document.ts +2 -3
- package/src/component/widget/navigation/_function/to-navigation-data/_to-navigation-group.ts +3 -4
- package/src/component/widget/navigation/_function/to-navigation-data/to-navigation-data.ts +6 -14
- package/src/component/widget/navigation/_type/navigation-data.ts +0 -12
- package/src/component/widget/navigation/_type/navigation-focus-snapshot.ts +0 -4
- package/src/component/widget/navigation/_wg-navigation-nav-list.css +5 -136
- package/src/component/widget/navigation/_wg-navigation-nav-list.tsx +10 -55
- package/src/component/widget/navigation/_wg-navigation-nav.css +2 -8
- package/src/component/widget/navigation/_wg-navigation-nav.tsx +1 -11
- package/src/component/widget/navigation/_wg-navigation-toc.css +12 -207
- package/src/component/widget/navigation/_wg-navigation-toc.tsx +39 -80
- package/src/component/widget/navigation/wg-navigation.css +1 -1
- package/src/component/widget/navigation/wg-navigation.tsx +10 -69
- package/src/component/widget/prose/wg-prose.css +7 -4
- package/src/component/widget/shell/wg-shell.css +7 -11
- package/src/constant/copy.ts +0 -5
- package/src/constant/font.ts +4 -9
- package/src/entry/browser/browser.tsx +1 -1
- package/src/entry/cli/cli.test.ts +6 -8
- package/src/entry/cli/cli.ts +7 -12
- package/src/store/navigation/create-navigation-stores.test.ts +10 -28
- package/src/store/navigation/create-navigation-stores.ts +4 -18
- package/src/store/navigation/navigation-state.ts +0 -10
- package/src/store/navigation/navigation-storage.ts +0 -5
- package/src/style/token.css +21 -20
- package/src/util/font/to-font-css.test.ts +2 -2
- package/src/util/mermaid/render-flow.js +2 -2
- package/src/asset/font/jetbrains-mono/jetbrains-mono-latin-wght-normal.woff2 +0 -0
- package/src/asset/font/jetbrains-mono/jetbrains-mono.css +0 -11
- package/src/asset/font/pretendard/pretendardvariable-dynamic-subset.css +0 -1008
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.0.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.1.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.10.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.11.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.12.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.13.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.14.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.15.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.16.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.17.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.18.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.19.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.2.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.20.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.21.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.22.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.23.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.24.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.25.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.26.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.27.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.28.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.29.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.3.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.30.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.31.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.32.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.33.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.34.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.35.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.36.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.37.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.38.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.39.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.4.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.40.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.41.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.42.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.43.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.44.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.45.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.46.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.47.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.48.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.49.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.5.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.50.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.51.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.52.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.53.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.54.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.55.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.56.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.57.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.58.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.59.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.6.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.60.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.61.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.62.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.63.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.64.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.65.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.66.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.67.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.68.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.69.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.7.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.70.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.71.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.72.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.73.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.74.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.75.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.76.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.77.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.78.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.79.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.8.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.80.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.81.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.82.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.83.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.84.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.85.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.86.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.87.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.88.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.89.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.9.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.90.woff2 +0 -0
- package/src/asset/font/pretendard/woff2-dynamic-subset/PretendardVariable.subset.91.woff2 +0 -0
- package/src/component/widget/navigation/_function/to-navigation-branch-id.ts +0 -6
- package/src/component/widget/navigation/_wg-navigation-branch-toggle.css +0 -28
- package/src/component/widget/navigation/_wg-navigation-branch-toggle.tsx +0 -48
- package/src/store/navigation/_constant/tree.ts +0 -6
- package/src/store/navigation/to-navigation-tree-state.ts +0 -19
- package/src/store/navigation/use-navigation-tree-store.ts +0 -12
|
@@ -130,15 +130,15 @@
|
|
|
130
130
|
margin: 4px 0 0;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
/* JetBrains Mono 합자 비활성 · >=, != 원문 구분 */
|
|
134
133
|
& code {
|
|
135
134
|
padding: 1px 3px;
|
|
136
135
|
border-radius: var(--app-radius-inline);
|
|
137
136
|
background: var(--app-color-code);
|
|
138
137
|
color: var(--app-color-text-strong);
|
|
139
|
-
|
|
138
|
+
|
|
139
|
+
/* UA monospace 대신 부모 글꼴 · 문단은 본문 정책, 코드 블록은 pre의 고정폭·자간 0 */
|
|
140
|
+
font-family: inherit;
|
|
140
141
|
font-size: 1em;
|
|
141
|
-
font-variant-ligatures: none;
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
/* 코드 블록 · Shiki의 --app-code-* 참조 */
|
|
@@ -151,8 +151,8 @@
|
|
|
151
151
|
background: var(--app-color-code);
|
|
152
152
|
font-family: var(--app-font-mono);
|
|
153
153
|
font-size: var(--app-font-size-detail);
|
|
154
|
-
font-variant-ligatures: none;
|
|
155
154
|
line-height: var(--app-line-height-code);
|
|
155
|
+
letter-spacing: 0;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
& pre code {
|
|
@@ -323,6 +323,9 @@
|
|
|
323
323
|
margin: var(--app-space-block) 0;
|
|
324
324
|
padding: var(--app-space-block) 0;
|
|
325
325
|
|
|
326
|
+
/* 라벨 위치는 자간 0의 격자로 계산 */
|
|
327
|
+
letter-spacing: 0;
|
|
328
|
+
|
|
326
329
|
/* stylelint-disable-next-line selector-disallowed-list -- 외부 렌더러 생성 SVG */
|
|
327
330
|
& svg {
|
|
328
331
|
display: block;
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* 넓은 화면은 같은 폭의 양쪽 탐색 · 좁은 화면은 문서 탐색만 표시
|
|
2
|
+
* 넓은 화면은 같은 폭의 양쪽 탐색 사이를 본문이 채움 · 좁은 화면은 문서 탐색만 표시
|
|
3
3
|
*/
|
|
4
4
|
.wg_shell__root {
|
|
5
5
|
display: grid;
|
|
6
6
|
max-width: var(--app-size-page);
|
|
7
7
|
margin: 0 auto;
|
|
8
8
|
padding: 0 var(--app-space-gutter);
|
|
9
|
-
grid-template: "nav main outline" 1fr / calc(var(--app-size-sidebar) + var(--app-space-sidebar-gap)) minmax(0, var(--app-size-
|
|
10
|
-
var(--app-size-sidebar) +
|
|
11
|
-
var(--app-space-sidebar-gap)
|
|
12
|
-
);
|
|
9
|
+
grid-template: "nav main outline" 1fr / calc(var(--app-size-sidebar) + var(--app-space-sidebar-gap)) minmax(0, 1fr) calc(var(--app-size-sidebar) + var(--app-space-sidebar-gap));
|
|
13
10
|
background: var(--app-color-ground);
|
|
14
11
|
color: var(--app-color-text);
|
|
15
|
-
font-family: var(--app-font-
|
|
12
|
+
font-family: var(--app-font-body);
|
|
16
13
|
font-size: var(--app-font-size-body);
|
|
17
14
|
line-height: var(--app-line-height-body);
|
|
15
|
+
letter-spacing: var(--app-letter-spacing-body);
|
|
18
16
|
|
|
19
17
|
/* 한국어 낱말 단위 줄바꿈 · 긴 식별자만 예외 */
|
|
20
18
|
word-break: keep-all;
|
|
@@ -35,7 +33,6 @@
|
|
|
35
33
|
.wg_shell__main {
|
|
36
34
|
grid-area: main;
|
|
37
35
|
min-width: 0;
|
|
38
|
-
max-width: var(--app-size-main);
|
|
39
36
|
border-inline: 1px solid var(--app-color-border-layout);
|
|
40
37
|
|
|
41
38
|
/* 문서 목록의 시작선 · 마지막 절도 읽는 선까지 이동 가능한 끝 여백 */
|
|
@@ -43,17 +40,16 @@
|
|
|
43
40
|
padding-inline: var(--app-space-column);
|
|
44
41
|
}
|
|
45
42
|
|
|
46
|
-
/*
|
|
47
|
-
@media (width <
|
|
43
|
+
/* 본문 최소 약 800px을 남기도록 목차 숨김 · 본문이 오른쪽 여백까지 채움 */
|
|
44
|
+
@media (width < 1360px) {
|
|
48
45
|
.wg_shell__root {
|
|
49
|
-
grid-template: "nav main
|
|
46
|
+
grid-template: "nav main" 1fr / calc(var(--app-size-sidebar) + var(--app-space-sidebar-gap)) minmax(0, 1fr);
|
|
50
47
|
}
|
|
51
48
|
}
|
|
52
49
|
|
|
53
50
|
/* 모바일의 브랜드·본문은 한 열 배치 */
|
|
54
51
|
@media (width < 1024px) {
|
|
55
52
|
.wg_shell__root {
|
|
56
|
-
max-width: calc(var(--app-size-main) + var(--app-space-gutter) * 2);
|
|
57
53
|
grid-template:
|
|
58
54
|
"nav" auto
|
|
59
55
|
"main" 1fr / minmax(0, 1fr);
|
package/src/constant/copy.ts
CHANGED
|
@@ -47,11 +47,6 @@ export const copy_error_home_clash = "홈 README가 겹친다";
|
|
|
47
47
|
*/
|
|
48
48
|
export const copy_error_prefix = "for-humanity";
|
|
49
49
|
|
|
50
|
-
/**
|
|
51
|
-
* 내장 본문 글꼴의 공통 조각이 누락된 패키지 오류
|
|
52
|
-
*/
|
|
53
|
-
export const copy_error_font_preload = "Missing bundled font for preload";
|
|
54
|
-
|
|
55
50
|
/**
|
|
56
51
|
* 미지원 명령 오류
|
|
57
52
|
*/
|
package/src/constant/font.ts
CHANGED
|
@@ -4,25 +4,20 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* 본문 글꼴 CSS · 패키지 기준 경로 ·
|
|
7
|
+
* 본문 영문·코드·흐름도 글꼴 CSS · 패키지 기준 경로 · Regular·SemiBold 두 파일
|
|
8
8
|
*/
|
|
9
|
-
export const
|
|
9
|
+
export const font_mono_css = "src/asset/font/monoplex-kr/monoplex-kr.css";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* 본문 한글 글꼴 CSS · IBM Plex Sans KR Regular·SemiBold · 한글 unicode-range
|
|
13
13
|
*/
|
|
14
|
-
export const
|
|
14
|
+
export const font_body_css = "src/asset/font/ibm-plex-sans-kr/ibm-plex-sans-kr.css";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* 사이트 이름 글꼴 CSS · Architects Daughter Regular · 라틴 subset
|
|
18
18
|
*/
|
|
19
19
|
export const font_brand_css = "src/asset/font/architects-daughter/architects-daughter.css";
|
|
20
20
|
|
|
21
|
-
/**
|
|
22
|
-
* 탐색·라틴 문자에 필요한 본문 조각 · 92개 전체 선요청 방지
|
|
23
|
-
*/
|
|
24
|
-
export const font_sans_preload_file = "PretendardVariable.subset.91.woff2";
|
|
25
|
-
|
|
26
21
|
/**
|
|
27
22
|
* 늦게 받은 글꼴로 이미 보이는 대체 글꼴을 교체하지 않는 표시 정책
|
|
28
23
|
*/
|
|
@@ -13,7 +13,7 @@ if (root !== null && payload !== null) {
|
|
|
13
13
|
try {
|
|
14
14
|
const value: unknown = JSON.parse(payload.textContent);
|
|
15
15
|
const data = navigationDataSchema.parse(value);
|
|
16
|
-
const stores = createNavigationStores({
|
|
16
|
+
const stores = createNavigationStores({session: () => sessionStorage});
|
|
17
17
|
createRoot(root).render(<WgShellControls data={data} stores={stores} reload={root.hasAttribute("data-shell-reload")} />);
|
|
18
18
|
} catch (error) {
|
|
19
19
|
// 초기화 오류에서도 서버의 링크·본문과 네이티브 스크롤 유지
|
|
@@ -314,12 +314,11 @@ test("nested groups follow metadata paths and keep sibling branches and document
|
|
|
314
314
|
const html = toNavigationHtml({site, docs, current: "authoring"});
|
|
315
315
|
|
|
316
316
|
assert.match(html, /href="\/authoring\/"[^>]*aria-current="page"/);
|
|
317
|
-
assert.match(html, /Atlas<\/span><
|
|
318
|
-
assert.match(html, /Research<\/span><
|
|
317
|
+
assert.match(html, /Atlas<\/span><ul\b/);
|
|
318
|
+
assert.match(html, /Research<\/span><ul\b/);
|
|
319
319
|
assert.equal([...html.matchAll(/href="\/authoring\/"/g)].length, 1);
|
|
320
320
|
assert.equal([...html.matchAll(/>Research<\/span>/g)].length, 2);
|
|
321
|
-
assert.
|
|
322
|
-
assert.doesNotMatch(toNavigationHtml({site, docs}), /aria-current="page"|wg_navigationNavList__item--current/);
|
|
321
|
+
assert.doesNotMatch(toNavigationHtml({site, docs}), /aria-current="page"/);
|
|
323
322
|
assert.ok(html.indexOf('href="/parts/"') < html.indexOf('href="/authoring/"'));
|
|
324
323
|
assert.doesNotMatch(html, /<details\b/);
|
|
325
324
|
});
|
|
@@ -370,17 +369,16 @@ test("parent documents contain ordered descendants with independent URLs and one
|
|
|
370
369
|
assert.deepEqual(toDocGroups({docs: docs.toReversed(), navigation: site.navigation}), groups);
|
|
371
370
|
|
|
372
371
|
const html = toNavigationHtml({site, docs, current: "details"});
|
|
373
|
-
assert.match(html, /href="\/settings\/"[^>]*>Settings<\/a><
|
|
374
|
-
assert.match(html, /href="\/guide\/site\/"[^>]*>Site<\/a><
|
|
372
|
+
assert.match(html, /href="\/settings\/"[^>]*>Settings<\/a><ul\b[^>]*aria-label="Settings"/);
|
|
373
|
+
assert.match(html, /href="\/guide\/site\/"[^>]*>Site<\/a><ul\b[^>]*aria-label="Site"/);
|
|
375
374
|
assert.match(html, /href="\/details\/"[^>]*aria-current="page"/);
|
|
376
375
|
assert.equal([...html.matchAll(/aria-current="page"/g)].length, 1);
|
|
377
376
|
assert.equal([...html.matchAll(/wg_navigationNavList__link--active/g)].length, 1);
|
|
378
|
-
assert.equal([...html.matchAll(/wg_navigationNavList__item--current/g)].length, 5);
|
|
379
377
|
for (const doc of docs) {
|
|
380
378
|
assert.equal(html.split(`href="/${doc.id}/"`).length - 1, 1);
|
|
381
379
|
}
|
|
382
380
|
assert.ok(html.indexOf('href="/themes/"') < html.indexOf('href="/guide/site/"'));
|
|
383
|
-
assert.doesNotMatch(toNavigationHtml({site, docs}), /aria-current="page"
|
|
381
|
+
assert.doesNotMatch(toNavigationHtml({site, docs}), /aria-current="page"/);
|
|
384
382
|
|
|
385
383
|
const app = createApp({
|
|
386
384
|
site,
|
package/src/entry/cli/cli.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import {EventEmitter} from "node:events";
|
|
8
8
|
import {existsSync, readFileSync, watch} from "node:fs";
|
|
9
9
|
import {copyFile, mkdir, rm, writeFile} from "node:fs/promises";
|
|
10
|
-
import {
|
|
10
|
+
import {dirname, extname, join, relative, resolve, sep} from "node:path";
|
|
11
11
|
import {fileURLToPath, pathToFileURL} from "node:url";
|
|
12
12
|
import {serve} from "@hono/node-server";
|
|
13
13
|
import {serveStatic} from "@hono/node-server/serve-static";
|
|
@@ -15,8 +15,8 @@ import {debounce} from "es-toolkit";
|
|
|
15
15
|
import {Hono} from "hono";
|
|
16
16
|
import {toSSG} from "hono/ssg";
|
|
17
17
|
import {asset_favicon_path, asset_font_dir, asset_media_extensions, asset_style_path} from "@/constant/asset";
|
|
18
|
-
import {copy_error_config,
|
|
19
|
-
import {font_brand_css, font_cache_control, font_mono_css
|
|
18
|
+
import {copy_error_config, copy_error_prefix, copy_error_unknown_command} from "@/constant/copy";
|
|
19
|
+
import {font_body_css, font_brand_css, font_cache_control, font_mono_css} from "@/constant/font";
|
|
20
20
|
import {site_config_absent} from "@/constant/site";
|
|
21
21
|
import {cli_config_file_name, cli_default_command, cli_default_docs_dir, cli_dev_port, cli_reload_delay_ms} from "@/entry/cli/_constant/cli";
|
|
22
22
|
import {crawling_reserved_roots} from "@/entry/cli/_constant/crawling";
|
|
@@ -77,23 +77,18 @@ const main = async () => {
|
|
|
77
77
|
|
|
78
78
|
const siteConfig = parsedConfig.data;
|
|
79
79
|
// 내장 @font-face와 파일 수집 · font-family는 token.css 소유
|
|
80
|
-
const sans = toFontCss({css: join(kitRoot, font_sans_css), fontDir: asset_font_dir});
|
|
81
80
|
const mono = toFontCss({css: join(kitRoot, font_mono_css), fontDir: asset_font_dir});
|
|
81
|
+
const body = toFontCss({css: join(kitRoot, font_body_css), fontDir: asset_font_dir});
|
|
82
82
|
const brand = toFontCss({css: join(kitRoot, font_brand_css), fontDir: asset_font_dir});
|
|
83
|
-
const sansPreload = [...sans.files].find((entry) => basename(entry[1]) === font_sans_preload_file);
|
|
84
83
|
|
|
85
|
-
|
|
86
|
-
throw new Error(`${copy_error_font_preload}: ${font_sans_preload_file}`);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const fontCss = [sans.css, mono.css, brand.css].join("\n");
|
|
84
|
+
const fontCss = [mono.css, body.css, brand.css].join("\n");
|
|
90
85
|
const stylePath = toAssetPath({path: asset_style_path, file: join(kitRoot, "dist/cli.css")});
|
|
91
86
|
const browserScript = readFileSync(join(kitRoot, "dist/browser.js"), "utf8");
|
|
92
87
|
const kitFiles = new Map([
|
|
93
88
|
[stylePath, join(kitRoot, "dist/cli.css")],
|
|
94
89
|
[asset_favicon_path, join(kitRoot, "src/asset/favicon.svg")],
|
|
95
|
-
...sans.files,
|
|
96
90
|
...mono.files,
|
|
91
|
+
...body.files,
|
|
97
92
|
...brand.files,
|
|
98
93
|
]);
|
|
99
94
|
const files = new Map(kitFiles);
|
|
@@ -107,7 +102,7 @@ const main = async () => {
|
|
|
107
102
|
const app = createApp({
|
|
108
103
|
site: siteConfig,
|
|
109
104
|
store,
|
|
110
|
-
assets: {stylePath, browserScript, fontCss, preload: [...brand.files.keys(),
|
|
105
|
+
assets: {stylePath, browserScript, fontCss, preload: [...brand.files.keys(), ...mono.files.keys(), ...body.files.keys()], reload: command === "dev"},
|
|
111
106
|
});
|
|
112
107
|
|
|
113
108
|
if (command === "build") {
|
|
@@ -1,35 +1,25 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import {test} from "node:test";
|
|
3
3
|
import {createNavigationStores} from "@/store/navigation/create-navigation-stores";
|
|
4
|
-
import {navigation_scroll_storage_key
|
|
4
|
+
import {navigation_scroll_storage_key} from "@/store/navigation/navigation-storage";
|
|
5
5
|
|
|
6
6
|
const fixture = () => {
|
|
7
|
-
const local = new Map<string, string>();
|
|
8
7
|
const session = new Map<string, string>();
|
|
9
|
-
const storage =
|
|
8
|
+
const storage = {
|
|
10
9
|
getItem: (key: string) => {
|
|
11
|
-
const value =
|
|
10
|
+
const value = session.get(key);
|
|
12
11
|
return value === undefined ? null : value;
|
|
13
12
|
},
|
|
14
13
|
setItem: (key: string, value: string) => {
|
|
15
|
-
|
|
14
|
+
session.set(key, value);
|
|
16
15
|
},
|
|
17
16
|
removeItem: (key: string) => {
|
|
18
|
-
|
|
17
|
+
session.delete(key);
|
|
19
18
|
},
|
|
20
|
-
}
|
|
21
|
-
return {
|
|
19
|
+
};
|
|
20
|
+
return {session, options: {session: () => storage}};
|
|
22
21
|
};
|
|
23
22
|
|
|
24
|
-
test("starts with every branch expanded and persists explicit choices across pages", () => {
|
|
25
|
-
const setup = fixture();
|
|
26
|
-
const stores = createNavigationStores(setup.options);
|
|
27
|
-
assert.deepEqual(stores.tree.getState(), {collapsed: {}});
|
|
28
|
-
stores.tree.setState({collapsed: {'group:["Projects"]': true, "outline:one:heading:setup": false}});
|
|
29
|
-
assert.deepEqual(createNavigationStores(setup.options).tree.getState(), stores.tree.getState());
|
|
30
|
-
assert.equal(setup.session.has(navigation_tree_storage_key), false);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
23
|
test("retains independent wide, desktop and drawer scroll positions within a tab", () => {
|
|
34
24
|
const setup = fixture();
|
|
35
25
|
const stores = createNavigationStores(setup.options);
|
|
@@ -41,23 +31,19 @@ test("retains independent wide, desktop and drawer scroll positions within a tab
|
|
|
41
31
|
},
|
|
42
32
|
});
|
|
43
33
|
assert.deepEqual(createNavigationStores(setup.options).scroll.getState(), stores.scroll.getState());
|
|
44
|
-
assert.equal(setup.local.has(navigation_scroll_storage_key), false);
|
|
45
34
|
});
|
|
46
35
|
|
|
47
36
|
test("rejects malformed and unknown-version persistence without losing defaults", () => {
|
|
48
|
-
for (const value of ["{", "null", '{"state":null,"version":1}', '{"state":{"
|
|
37
|
+
for (const value of ["{", "null", '{"state":null,"version":1}', '{"state":{"positions":{}},"version":999}']) {
|
|
49
38
|
const setup = fixture();
|
|
50
|
-
setup.local.set(navigation_tree_storage_key, value);
|
|
51
39
|
setup.session.set(navigation_scroll_storage_key, value);
|
|
52
40
|
const stores = createNavigationStores(setup.options);
|
|
53
|
-
assert.deepEqual(stores.tree.getState(), {collapsed: {}});
|
|
54
41
|
assert.deepEqual(stores.scroll.getState(), {positions: {}});
|
|
55
42
|
}
|
|
56
43
|
});
|
|
57
44
|
|
|
58
|
-
test("
|
|
45
|
+
test("rejects invalid scroll coordinates", () => {
|
|
59
46
|
const setup = fixture();
|
|
60
|
-
setup.local.set(navigation_tree_storage_key, JSON.stringify({version: 1, state: {collapsed: {good: true, bad: "true"}, unexpected: true}}));
|
|
61
47
|
setup.session.set(
|
|
62
48
|
navigation_scroll_storage_key,
|
|
63
49
|
JSON.stringify({
|
|
@@ -72,7 +58,6 @@ test("narrows persisted branch flags and rejects invalid scroll coordinates", ()
|
|
|
72
58
|
}),
|
|
73
59
|
);
|
|
74
60
|
const stores = createNavigationStores(setup.options);
|
|
75
|
-
assert.deepEqual(stores.tree.getState(), {collapsed: {good: true}});
|
|
76
61
|
assert.deepEqual(stores.scroll.getState().positions.wide, {navigation: "docs", pathname: "/one/", documents: 100, outline: 20});
|
|
77
62
|
assert.equal(stores.scroll.getState().positions.desktop, undefined);
|
|
78
63
|
assert.equal(stores.scroll.getState().positions.drawer, undefined);
|
|
@@ -82,10 +67,7 @@ test("keeps in-memory interaction working when storage reads and writes are bloc
|
|
|
82
67
|
const blocked = () => {
|
|
83
68
|
throw new Error("Storage blocked");
|
|
84
69
|
};
|
|
85
|
-
const stores = createNavigationStores({
|
|
86
|
-
stores.tree.setState({collapsed: {"document:one": true}});
|
|
87
|
-
stores.tree.persist.rehydrate();
|
|
88
|
-
assert.equal(stores.tree.getState().collapsed["document:one"], true);
|
|
70
|
+
const stores = createNavigationStores({session: blocked});
|
|
89
71
|
stores.scroll.setState({positions: {desktop: {navigation: "docs", pathname: "/", documents: 100, outline: 200}}});
|
|
90
72
|
stores.scroll.persist.rehydrate();
|
|
91
73
|
assert.equal(stores.scroll.getState().positions.desktop?.documents, 100);
|
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
import {createJSONStorage, persist, type StateStorage} from "zustand/middleware";
|
|
2
2
|
import {createStore} from "zustand/vanilla";
|
|
3
|
-
import type {NavigationScrollState
|
|
4
|
-
import {navigation_scroll_storage_key, navigation_storage_version
|
|
3
|
+
import type {NavigationScrollState} from "@/store/navigation/navigation-state";
|
|
4
|
+
import {navigation_scroll_storage_key, navigation_storage_version} from "@/store/navigation/navigation-storage";
|
|
5
5
|
import {toNavigationScrollState} from "@/store/navigation/to-navigation-scroll-state";
|
|
6
|
-
import {toNavigationTreeState} from "@/store/navigation/to-navigation-tree-state";
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* 브라우저 저장소를 늦게 읽는 경계 · 차단 환경과 테스트의 메모리 저장소 지원
|
|
10
9
|
*/
|
|
11
10
|
interface NavigationStorage {
|
|
12
|
-
/**
|
|
13
|
-
* 브라우저 재실행 후에도 유지할 접힘 선택
|
|
14
|
-
*/
|
|
15
|
-
local: () => StateStorage;
|
|
16
11
|
/**
|
|
17
12
|
* 같은 탭 안에서만 복원할 스크롤 위치
|
|
18
13
|
*/
|
|
@@ -25,9 +20,9 @@ interface NavigationStorage {
|
|
|
25
20
|
*/
|
|
26
21
|
export const createNavigationStores = (options: NavigationStorage) => {
|
|
27
22
|
/**
|
|
28
|
-
* 저장소 접근이 막혀도 persist 갱신이
|
|
23
|
+
* 저장소 접근이 막혀도 persist 갱신이 스크롤 동작을 중단하지 않도록 격리
|
|
29
24
|
*/
|
|
30
|
-
const toSafeStorage = (getStorage: NavigationStorage["
|
|
25
|
+
const toSafeStorage = (getStorage: NavigationStorage["session"]): StateStorage => {
|
|
31
26
|
return {
|
|
32
27
|
getItem: (key) => {
|
|
33
28
|
// persist의 읽기 오류 경로로 보내 기존 메모리 상태를 유지 · null은 실제 저장소 초기화에만 사용
|
|
@@ -51,15 +46,6 @@ export const createNavigationStores = (options: NavigationStorage) => {
|
|
|
51
46
|
};
|
|
52
47
|
|
|
53
48
|
return {
|
|
54
|
-
tree: createStore<NavigationTreeState>()(
|
|
55
|
-
persist(() => ({collapsed: {}}), {
|
|
56
|
-
name: navigation_tree_storage_key,
|
|
57
|
-
version: navigation_storage_version,
|
|
58
|
-
storage: createJSONStorage(() => toSafeStorage(options.local)),
|
|
59
|
-
merge: (persisted) => toNavigationTreeState(persisted),
|
|
60
|
-
migrate: () => ({collapsed: {}}),
|
|
61
|
-
}),
|
|
62
|
-
),
|
|
63
49
|
scroll: createStore<NavigationScrollState>()(
|
|
64
50
|
persist(() => ({positions: {}}), {
|
|
65
51
|
name: navigation_scroll_storage_key,
|
|
@@ -3,16 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export type NavigationLayout = "wide" | "desktop" | "drawer";
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* 사용자가 명시적으로 바꾼 가지 선택 · 없는 키는 펼침
|
|
8
|
-
*/
|
|
9
|
-
export interface NavigationTreeState {
|
|
10
|
-
/**
|
|
11
|
-
* 문서 ID·그룹 전체 경로·페이지별 heading으로 구분한 접힘 상태
|
|
12
|
-
*/
|
|
13
|
-
collapsed: Record<string, boolean>;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
6
|
/**
|
|
17
7
|
* 한 화면 배치의 마지막 탐색 위치 · 목록 변경과 다른 페이지의 목차는 재사용하지 않음
|
|
18
8
|
*/
|
package/src/style/token.css
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* 공통 토큰의 단일 출처 · --app-종류-쓰임
|
|
3
3
|
* 사용 기준: templates/document/design.md · 테마 분기는 color-scheme에 한정
|
|
4
|
-
* 폭 기준
|
|
4
|
+
* 폭 기준 1360px·1024px·640px · 양쪽 탐색과 본문 배치
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
:root {
|
|
@@ -48,16 +48,16 @@
|
|
|
48
48
|
|
|
49
49
|
/*
|
|
50
50
|
* 내장 글꼴 · CLI는 @font-face와 자원 URL 생성
|
|
51
|
-
*
|
|
52
|
-
* 영문 폭 0.
|
|
51
|
+
* 본문·라벨·인라인 코드 한글 IBM Plex Sans KR·영문 Monoplex KR · 코드 블록·흐름도 Monoplex KR · 사이트 이름 Architects Daughter
|
|
52
|
+
* 영문 폭 0.528em = 흐름도 12px 격자의 6.336px · 코드 블록·흐름도의 한글은 정확히 2칸
|
|
53
|
+
* 본문 맨 앞의 IBM Plex Sans KR은 한글 unicode-range만 담당 · 영문·숫자·기호는 다음 순서의 Monoplex KR
|
|
53
54
|
*/
|
|
54
|
-
--app-font-
|
|
55
|
-
--app-font-
|
|
56
|
-
--app-font-brand: "Architects Daughter", var(--app-font-
|
|
55
|
+
--app-font-mono: "Monoplex KR", ui-monospace, monospace;
|
|
56
|
+
--app-font-body: "IBM Plex Sans KR", var(--app-font-mono);
|
|
57
|
+
--app-font-brand: "Architects Daughter", var(--app-font-body);
|
|
57
58
|
|
|
58
59
|
/* 글자 크기 · 11px 비상호작용 묶음 · 12px 기본과 역할별 제목 크기 */
|
|
59
60
|
--app-font-size-group: 11px;
|
|
60
|
-
--app-font-size-label: 12px;
|
|
61
61
|
--app-font-size-detail: 12px;
|
|
62
62
|
--app-font-size-dense: 12px;
|
|
63
63
|
--app-font-size-body: 12px;
|
|
@@ -72,18 +72,18 @@
|
|
|
72
72
|
--app-font-weight-strong: 600;
|
|
73
73
|
--app-font-weight-title: 600;
|
|
74
74
|
|
|
75
|
-
/* 행간 · 작은 제목·탐색은 1.
|
|
75
|
+
/* 행간 · 작은 제목·탐색은 1.4, 본문은 한글 획 사이 여유 확보 */
|
|
76
76
|
--app-line-height-title: 1.5;
|
|
77
77
|
--app-line-height-heading: 1.5;
|
|
78
|
-
--app-line-height-tight: 1.
|
|
78
|
+
--app-line-height-tight: 1.4;
|
|
79
79
|
--app-line-height-code: 1.65;
|
|
80
80
|
--app-line-height-body: 1.7;
|
|
81
81
|
|
|
82
|
-
/* 자간 ·
|
|
83
|
-
--app-letter-spacing-
|
|
82
|
+
/* 자간 · 본문·라벨·인라인 코드를 조이고 제목은 그보다 조금 더 · 사이트 이름은 기본 폭 · 코드 블록·흐름도는 격자를 위해 0 */
|
|
83
|
+
--app-letter-spacing-body: -0.03em;
|
|
84
84
|
--app-letter-spacing-brand: 0;
|
|
85
|
-
--app-letter-spacing-heading: -0.
|
|
86
|
-
--app-letter-spacing-title: -0.
|
|
85
|
+
--app-letter-spacing-heading: -0.04em;
|
|
86
|
+
--app-letter-spacing-title: -0.045em;
|
|
87
87
|
|
|
88
88
|
/* 공통 간격 · margin·padding·gap의 리듬 · 단독 보정은 지역 값 */
|
|
89
89
|
--app-space-inline: 6px;
|
|
@@ -92,9 +92,10 @@
|
|
|
92
92
|
--app-space-group: 20px;
|
|
93
93
|
--app-space-section: 32px;
|
|
94
94
|
|
|
95
|
-
/* 탐색 트리 · 항목 위아래 여백·묶음
|
|
96
|
-
--app-space-tree-row:
|
|
97
|
-
--app-space-tree-
|
|
95
|
+
/* 탐색 트리 · 항목 위아래 여백·묶음 사이·묶음 라벨 아래·중첩 들여쓰기 */
|
|
96
|
+
--app-space-tree-row: 0px;
|
|
97
|
+
--app-space-tree-group: 16px;
|
|
98
|
+
--app-space-tree-label: 2px;
|
|
98
99
|
--app-space-tree-indent: 12px;
|
|
99
100
|
|
|
100
101
|
/* 페이지 틀 · 좁은 화면 값은 아래 @media */
|
|
@@ -102,15 +103,15 @@
|
|
|
102
103
|
--app-space-gutter: 28px;
|
|
103
104
|
--app-space-column: 32px;
|
|
104
105
|
--app-space-sidebar-gap: 32px;
|
|
105
|
-
--app-size-sidebar:
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
--app-size-sidebar: 200px;
|
|
107
|
+
|
|
108
|
+
/* 페이지 최대 폭 · 본문은 사이드바·간격을 뺀 나머지 전체 */
|
|
109
|
+
--app-size-page: 1920px;
|
|
108
110
|
--app-size-brand: calc(var(--app-font-size-title) * var(--app-line-height-title) + var(--app-space-page-top) + var(--app-space-group));
|
|
109
111
|
--app-size-mobile-header: 56px;
|
|
110
112
|
--app-size-menu-button: 44px;
|
|
111
113
|
--app-size-drawer: 320px;
|
|
112
114
|
--app-size-navigation-fade: 28px;
|
|
113
|
-
--app-size-tree-toggle: 24px;
|
|
114
115
|
|
|
115
116
|
/* 화면 위쪽 제목 여백 · hash 도착점과 목차 읽는 선의 공통 기준 */
|
|
116
117
|
--app-space-anchor: 80px;
|
|
@@ -4,11 +4,11 @@ import {tmpdir} from "node:os";
|
|
|
4
4
|
import {join} from "node:path";
|
|
5
5
|
import {test} from "node:test";
|
|
6
6
|
import {asset_font_dir} from "@/constant/asset";
|
|
7
|
-
import {font_brand_css, font_mono_css
|
|
7
|
+
import {font_body_css, font_brand_css, font_mono_css} from "@/constant/font";
|
|
8
8
|
import {toFontCss} from "@/util/font/to-font-css";
|
|
9
9
|
|
|
10
10
|
test("bundled fonts prevent a late swap after fallback text is visible", () => {
|
|
11
|
-
for (const css of [
|
|
11
|
+
for (const css of [font_mono_css, font_body_css, font_brand_css]) {
|
|
12
12
|
const result = toFontCss({css: join(process.cwd(), css), fontDir: asset_font_dir});
|
|
13
13
|
|
|
14
14
|
assert.match(result.css, /font-display:\s*optional;/);
|
|
@@ -82,7 +82,7 @@ function widenLabelGaps(rows) {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
function gridToSvg(ascii) {
|
|
85
|
-
const cw =
|
|
85
|
+
const cw = 6.336, ch = 17, fs = 12;
|
|
86
86
|
const rows = widenLabelGaps(ascii.replace(/\s+$/, "").split("\n"));
|
|
87
87
|
const cols = Math.max.apply(null, rows.map((r) => r.length));
|
|
88
88
|
const f = (n) => n.toFixed(1);
|
|
@@ -90,7 +90,7 @@ function gridToSvg(ascii) {
|
|
|
90
90
|
|
|
91
91
|
const isText = (chr) => chr !== undefined && chr !== " " && chr !== ZW && LINES[chr] === undefined && ARROWS[chr] === undefined && chr !== "◇";
|
|
92
92
|
const center = (c) => c * cw + cw / 2;
|
|
93
|
-
const textWidth = (chars) => chars.reduce((w, chr) => w + (WIDE.test(chr) ?
|
|
93
|
+
const textWidth = (chars) => chars.reduce((w, chr) => w + (WIDE.test(chr) ? cw * 2 : cw), 0);
|
|
94
94
|
|
|
95
95
|
rows.forEach((row, r) => {
|
|
96
96
|
const cy = r * ch + ch / 2, y0 = r * ch, y1 = y0 + ch;
|
|
Binary file
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/* JetBrains Mono Variable, Fontsource 5.3.0 의 latin 조각. 라이선스는 옆의 LICENSE (OFL) */
|
|
2
|
-
/* jetbrains-mono-latin-wght-normal */
|
|
3
|
-
@font-face {
|
|
4
|
-
font-family: "JetBrains Mono Variable";
|
|
5
|
-
font-style: normal;
|
|
6
|
-
font-display: swap;
|
|
7
|
-
font-weight: 100 800;
|
|
8
|
-
src: url(./jetbrains-mono-latin-wght-normal.woff2) format("woff2-variations");
|
|
9
|
-
unicode-range:
|
|
10
|
-
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
11
|
-
}
|