for-humanity 0.1.0
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 +14 -0
- package/LICENSE +21 -0
- package/README.md +118 -0
- package/dist/cli.css +962 -0
- package/dist/cli.js +1241 -0
- package/dist/client.js +5 -0
- package/package.json +92 -0
- package/src/app.tsx +57 -0
- package/src/asset/favicon.svg +5 -0
- package/src/asset/font/architects-daughter/LICENSE.txt +93 -0
- package/src/asset/font/architects-daughter/architects-daughter-latin-400-normal.woff2 +0 -0
- package/src/asset/font/architects-daughter/architects-daughter.css +10 -0
- package/src/asset/font/jetbrains-mono/LICENSE +93 -0
- package/src/asset/font/jetbrains-mono/jetbrains-mono-latin-wght-normal.woff2 +0 -0
- package/src/asset/font/jetbrains-mono/jetbrains-mono.css +11 -0
- package/src/asset/font/pretendard/LICENSE.txt +94 -0
- package/src/asset/font/pretendard/pretendardvariable-dynamic-subset.css +1008 -0
- 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/cli.ts +162 -0
- package/src/client.ts +322 -0
- package/src/component/widget/prose/_constant/heading-highlight.ts +4 -0
- package/src/component/widget/prose/_constant/section.ts +7 -0
- package/src/component/widget/prose/_constant/status.ts +9 -0
- package/src/component/widget/prose/_function/has-block-content.ts +30 -0
- package/src/component/widget/prose/_function/rehype-head.ts +31 -0
- package/src/component/widget/prose/_function/rehype-sections/_to-section-headings.ts +20 -0
- package/src/component/widget/prose/_function/rehype-sections/rehype-sections.ts +21 -0
- package/src/component/widget/prose/_function/rehype-tables.ts +22 -0
- package/src/component/widget/prose/_function/remark-blocks.ts +112 -0
- package/src/component/widget/prose/_function/remark-flow.ts +26 -0
- package/src/component/widget/prose/_function/remark-links.ts +33 -0
- package/src/component/widget/prose/_function/remark-parts.ts +26 -0
- package/src/component/widget/prose/_function/remark-status.ts +59 -0
- package/src/component/widget/prose/_function/remark-swatch.ts +16 -0
- package/src/component/widget/prose/_function/remark-unknown-directives.ts +25 -0
- package/src/component/widget/prose/_type/doc-section.ts +9 -0
- package/src/component/widget/prose/wg-prose.css +381 -0
- package/src/component/widget/prose/wg-prose.tsx +43 -0
- package/src/component/widget/shell/_constant/cursor-face.ts +9 -0
- package/src/component/widget/shell/_constant/navigation.ts +4 -0
- package/src/component/widget/shell/_constant/reading-line.ts +4 -0
- package/src/component/widget/shell/_function/bind-mobile-navigation.ts +140 -0
- package/src/component/widget/shell/_function/to-toc-groups.ts +38 -0
- package/src/component/widget/shell/_type/doc-outline.ts +16 -0
- package/src/component/widget/shell/_type/toc-group.ts +39 -0
- package/src/component/widget/shell/_wg-shell-nav.css +134 -0
- package/src/component/widget/shell/_wg-shell-nav.tsx +75 -0
- package/src/component/widget/shell/_wg-shell-toc.css +268 -0
- package/src/component/widget/shell/_wg-shell-toc.tsx +57 -0
- package/src/component/widget/shell/wg-shell.css +261 -0
- package/src/component/widget/shell/wg-shell.tsx +147 -0
- package/src/constant/asset.ts +48 -0
- package/src/constant/cli.ts +19 -0
- package/src/constant/copy.ts +108 -0
- package/src/constant/doc.ts +13 -0
- package/src/constant/font.ts +39 -0
- package/src/constant/locale.ts +9 -0
- package/src/constant/site.ts +9 -0
- package/src/constant/status.ts +15 -0
- package/src/content/create-processor.ts +59 -0
- package/src/content/read-docs.test.ts +242 -0
- package/src/content/read-docs.ts +75 -0
- package/src/content/read-home.ts +32 -0
- package/src/content/rehype-heading-ids.ts +34 -0
- package/src/content/remark-report.ts +15 -0
- package/src/content/to-doc-groups.ts +18 -0
- package/src/dev.ts +79 -0
- package/src/env.d.ts +6 -0
- package/src/page/doc/pg-doc.tsx +35 -0
- package/src/page/home/pg-home.tsx +40 -0
- package/src/style/base.css +28 -0
- package/src/style/token.css +162 -0
- package/src/type/doc-content.ts +15 -0
- package/src/type/doc-data.ts +33 -0
- package/src/type/doc-file-data.ts +21 -0
- package/src/type/doc-heading.ts +17 -0
- package/src/type/doc.ts +16 -0
- package/src/type/site-assets.ts +17 -0
- package/src/type/site-config.ts +55 -0
- package/src/type/vfile-data.d.ts +10 -0
- package/src/util/dom/find-hash-target.ts +18 -0
- package/src/util/dom/reveal-hash-target.ts +15 -0
- package/src/util/error/to-error-message.ts +10 -0
- package/src/util/font/to-font-css.test.ts +41 -0
- package/src/util/font/to-font-css.ts +28 -0
- package/src/util/mermaid/render-flow.js +321 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {takeWhile} from "es-toolkit/array";
|
|
2
|
+
import {section_heading_depth} from "@/component/widget/prose/_constant/section";
|
|
3
|
+
import type {DocOutline} from "@/component/widget/shell/_type/doc-outline";
|
|
4
|
+
import type {TocGroup, TocSection} from "@/component/widget/shell/_type/toc-group";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* h2별 h3 수집 · 가름 시작 절에서 목차 묶음 분리
|
|
8
|
+
* 첫 h2 앞의 h3은 목차 제외
|
|
9
|
+
*/
|
|
10
|
+
export const toTocGroups = (outline: DocOutline): TocGroup[] => {
|
|
11
|
+
const entries = outline.headings
|
|
12
|
+
.filter((heading) => heading.depth === section_heading_depth.section || heading.depth === section_heading_depth.sub)
|
|
13
|
+
.map((heading, index) => ({heading, section: outline.sections[index]}));
|
|
14
|
+
const sections = entries.flatMap((entry, index): TocSection[] =>
|
|
15
|
+
entry.heading.depth === section_heading_depth.section
|
|
16
|
+
? [
|
|
17
|
+
{
|
|
18
|
+
heading: entry.heading,
|
|
19
|
+
part: entry.section.part,
|
|
20
|
+
subs: takeWhile(entries.slice(index + 1), (sub) => sub.heading.depth !== section_heading_depth.section).map((sub) => ({
|
|
21
|
+
heading: sub.heading,
|
|
22
|
+
})),
|
|
23
|
+
},
|
|
24
|
+
]
|
|
25
|
+
: [],
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
return sections.flatMap((section, index) =>
|
|
29
|
+
index === 0 || section.part !== undefined
|
|
30
|
+
? [
|
|
31
|
+
{
|
|
32
|
+
part: section.part,
|
|
33
|
+
sections: [section, ...takeWhile(sections.slice(index + 1), (next) => next.part === undefined)],
|
|
34
|
+
},
|
|
35
|
+
]
|
|
36
|
+
: [],
|
|
37
|
+
);
|
|
38
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type {DocSection} from "@/component/widget/prose/_type/doc-section";
|
|
2
|
+
import type {DocHeading} from "@/type/doc-heading";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 문서 렌더링 결과의 목차 입력
|
|
6
|
+
*/
|
|
7
|
+
export interface DocOutline {
|
|
8
|
+
/**
|
|
9
|
+
* 작성한 제목의 id와 텍스트 · 문서 순서
|
|
10
|
+
*/
|
|
11
|
+
headings: DocHeading[];
|
|
12
|
+
/**
|
|
13
|
+
* 제목별 가름 · headings의 h2·h3 순서와 일치
|
|
14
|
+
*/
|
|
15
|
+
sections: DocSection[];
|
|
16
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type {DocHeading} from "@/type/doc-heading";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 목차 소제목 항목
|
|
5
|
+
*/
|
|
6
|
+
export interface TocSub {
|
|
7
|
+
/**
|
|
8
|
+
* 제목 id와 텍스트
|
|
9
|
+
*/
|
|
10
|
+
heading: DocHeading;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 목차 절과 소제목 목록
|
|
15
|
+
*/
|
|
16
|
+
export interface TocSection extends TocSub {
|
|
17
|
+
/**
|
|
18
|
+
* 이 절에서 시작하는 가름 이름
|
|
19
|
+
*/
|
|
20
|
+
part?: string;
|
|
21
|
+
/**
|
|
22
|
+
* 해당 절의 소제목 · 현재 위치와 무관하게 전체 표시
|
|
23
|
+
*/
|
|
24
|
+
subs: TocSub[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 가름별 목차 묶음 · 첫 묶음 이름 생략 가능
|
|
29
|
+
*/
|
|
30
|
+
export interface TocGroup {
|
|
31
|
+
/**
|
|
32
|
+
* 묶음 위의 가름 이름
|
|
33
|
+
*/
|
|
34
|
+
part?: string;
|
|
35
|
+
/**
|
|
36
|
+
* 묶음의 절 목록
|
|
37
|
+
*/
|
|
38
|
+
sections: TocSection[];
|
|
39
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 읽는 순서의 문서 목록 · 중립색 1px 트리
|
|
3
|
+
*/
|
|
4
|
+
.wg_shellNav__root {
|
|
5
|
+
font-size: var(--app-font-size-dense);
|
|
6
|
+
line-height: var(--app-line-height-tight);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.wg_shellNav__docs {
|
|
10
|
+
display: flex;
|
|
11
|
+
flex-direction: column;
|
|
12
|
+
gap: var(--app-space-stack);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.wg_shellNav__list {
|
|
16
|
+
margin: 0 0 0 var(--app-space-tree-inset);
|
|
17
|
+
padding: 0;
|
|
18
|
+
list-style: none;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.wg_shellNav__item {
|
|
22
|
+
/* 세로 줄기는 각 항목 기준 · 마지막 항목의 첫 줄 가운데에서 종료 */
|
|
23
|
+
position: relative;
|
|
24
|
+
|
|
25
|
+
&::before {
|
|
26
|
+
position: absolute;
|
|
27
|
+
top: 0;
|
|
28
|
+
bottom: 0;
|
|
29
|
+
left: 0;
|
|
30
|
+
border-left: 1px solid var(--app-color-border-soft);
|
|
31
|
+
content: "";
|
|
32
|
+
pointer-events: none;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&:where(:last-child)::before {
|
|
36
|
+
bottom: auto;
|
|
37
|
+
height: calc(0.5lh + var(--app-space-tree-row));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* hover·키보드 포커스의 도착점 · 첫 줄 아래는 기본 줄기 유지 */
|
|
41
|
+
&::after {
|
|
42
|
+
position: absolute;
|
|
43
|
+
top: 0;
|
|
44
|
+
left: 0;
|
|
45
|
+
height: calc(0.5lh + var(--app-space-tree-row));
|
|
46
|
+
border-left: 1px solid transparent;
|
|
47
|
+
content: "";
|
|
48
|
+
pointer-events: none;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
&:where(:hover)::after {
|
|
52
|
+
border-left-color: var(--app-color-text-strong);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
&:where(:has(:focus-visible))::after {
|
|
56
|
+
border-left-color: var(--app-color-text-strong);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* 뒤 항목까지의 세로 경로 · 같은 목록의 형제 안에서만 연결 */
|
|
60
|
+
&:where(:has(~ .wg_shellNav__item:hover))::before {
|
|
61
|
+
border-left-color: var(--app-color-text-strong);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
&:where(:has(~ .wg_shellNav__item :focus-visible))::before {
|
|
65
|
+
border-left-color: var(--app-color-text-strong);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.wg_shellNav__item--trail {
|
|
70
|
+
&::before {
|
|
71
|
+
border-left-color: var(--app-color-text-strong);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.wg_shellNav__item--current {
|
|
76
|
+
&::after {
|
|
77
|
+
border-left-color: var(--app-color-text-strong);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.wg_shellNav__link {
|
|
82
|
+
/* 가로 가지는 링크 첫 줄 기준 · 여러 줄 제목에서도 연결 위치 유지 */
|
|
83
|
+
position: relative;
|
|
84
|
+
display: block;
|
|
85
|
+
padding: var(--app-space-tree-row) 0 var(--app-space-tree-row) calc(var(--app-space-tree-indent) + var(--app-space-inline));
|
|
86
|
+
color: var(--app-color-text);
|
|
87
|
+
font-size: var(--app-font-size-dense);
|
|
88
|
+
line-height: var(--app-line-height-tight);
|
|
89
|
+
text-decoration: none;
|
|
90
|
+
|
|
91
|
+
&::before {
|
|
92
|
+
position: absolute;
|
|
93
|
+
top: calc(0.5lh + var(--app-space-tree-row));
|
|
94
|
+
left: 0;
|
|
95
|
+
width: var(--app-space-tree-indent);
|
|
96
|
+
border-top: 1px solid var(--app-color-border-soft);
|
|
97
|
+
content: "";
|
|
98
|
+
pointer-events: none;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
&:where(:hover) {
|
|
102
|
+
text-decoration: underline;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
&:where(:hover)::before {
|
|
106
|
+
border-top-color: currentcolor;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* hover와 같은 밑줄·가지선으로 키보드 위치 표시 */
|
|
110
|
+
&:where(:focus-visible) {
|
|
111
|
+
outline: none;
|
|
112
|
+
text-decoration: underline;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
&:where(:focus-visible)::before {
|
|
116
|
+
border-top-color: currentcolor;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.wg_shellNav__link--active {
|
|
121
|
+
color: var(--app-color-text-strong);
|
|
122
|
+
font-weight: var(--app-font-weight-active);
|
|
123
|
+
|
|
124
|
+
&::before {
|
|
125
|
+
border-top-color: currentcolor;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.wg_shellNav__group {
|
|
130
|
+
margin: 0 0 4px;
|
|
131
|
+
color: var(--app-color-text-muted);
|
|
132
|
+
font-size: var(--app-font-size-label);
|
|
133
|
+
text-box: trim-start cap alphabetic;
|
|
134
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import {copy_nav_aria_label} from "@/constant/copy";
|
|
3
|
+
import {toDocGroups} from "@/content/to-doc-groups";
|
|
4
|
+
import type {Doc} from "@/type/doc";
|
|
5
|
+
import type {SiteConfig} from "@/type/site-config";
|
|
6
|
+
import "./_wg-shell-nav.css";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 서버 사이드바 입력 · 읽는 순서의 문서 묶음
|
|
10
|
+
*/
|
|
11
|
+
export interface WgShellNavProps {
|
|
12
|
+
/**
|
|
13
|
+
* 문서 묶음 순서
|
|
14
|
+
*/
|
|
15
|
+
site: SiteConfig;
|
|
16
|
+
/**
|
|
17
|
+
* 전체 문서 목록
|
|
18
|
+
*/
|
|
19
|
+
docs: Doc[];
|
|
20
|
+
/**
|
|
21
|
+
* 현재 문서 id · 첫 화면 생략
|
|
22
|
+
*/
|
|
23
|
+
current?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const WgShellNav = (props: WgShellNavProps) => {
|
|
27
|
+
const docGroups = toDocGroups({docs: props.docs, navigation: props.site.navigation});
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<nav className={clsx("wg_shellNav__root")} aria-label={copy_nav_aria_label}>
|
|
31
|
+
{/**
|
|
32
|
+
* 문서 이동 · 독자 목적별 묶음
|
|
33
|
+
*/}
|
|
34
|
+
<div className={clsx("wg_shellNav__docs")}>
|
|
35
|
+
{/**
|
|
36
|
+
* 묶음 이름과 독립 문서 · 제목이 링크의 접근 가능한 이름
|
|
37
|
+
*/}
|
|
38
|
+
{docGroups.map((group) => {
|
|
39
|
+
const currentIndex = group.docs.findIndex((doc) => doc.id === props.current);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<section className={clsx("wg_shellNav__docGroup")} key={group.name} aria-label={group.name}>
|
|
43
|
+
<div className={clsx("wg_shellNav__group")}>{group.name}</div>
|
|
44
|
+
{/**
|
|
45
|
+
* 현재 문서와 묶음 시작부터 이어지는 세로 경로 표시
|
|
46
|
+
*/}
|
|
47
|
+
<ul className={clsx("wg_shellNav__list")}>
|
|
48
|
+
{group.docs.map((doc, index) => (
|
|
49
|
+
<li
|
|
50
|
+
className={clsx("wg_shellNav__item", {
|
|
51
|
+
"wg_shellNav__item--trail": index < currentIndex,
|
|
52
|
+
"wg_shellNav__item--current": index === currentIndex,
|
|
53
|
+
})}
|
|
54
|
+
key={doc.id}
|
|
55
|
+
>
|
|
56
|
+
<a
|
|
57
|
+
className={clsx("wg_shellNav__link", {
|
|
58
|
+
"wg_shellNav__link--active": index === currentIndex,
|
|
59
|
+
})}
|
|
60
|
+
href={`/${doc.id}/`}
|
|
61
|
+
title={doc.data.label}
|
|
62
|
+
aria-current={index === currentIndex ? "page" : undefined}
|
|
63
|
+
>
|
|
64
|
+
{doc.data.name}
|
|
65
|
+
</a>
|
|
66
|
+
</li>
|
|
67
|
+
))}
|
|
68
|
+
</ul>
|
|
69
|
+
</section>
|
|
70
|
+
);
|
|
71
|
+
})}
|
|
72
|
+
</div>
|
|
73
|
+
</nav>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 문서 탐색 아래 목차 · 작성한 제목과 계층을 유지하는 중립색 트리
|
|
3
|
+
*/
|
|
4
|
+
.wg_shellToc__root {
|
|
5
|
+
margin-top: var(--app-space-group);
|
|
6
|
+
padding-top: var(--app-space-group);
|
|
7
|
+
border-top: 1px solid var(--app-color-border-soft);
|
|
8
|
+
font-size: var(--app-font-size-dense);
|
|
9
|
+
line-height: var(--app-line-height-tight);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.wg_shellToc__label {
|
|
13
|
+
margin-bottom: var(--app-space-inline);
|
|
14
|
+
color: var(--app-color-text-muted);
|
|
15
|
+
font-size: var(--app-font-size-label);
|
|
16
|
+
font-weight: var(--app-font-weight-mark);
|
|
17
|
+
letter-spacing: var(--app-letter-spacing-label);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.wg_shellToc__group {
|
|
21
|
+
margin: var(--app-space-stack) 0 4px;
|
|
22
|
+
color: var(--app-color-text-muted);
|
|
23
|
+
font-size: var(--app-font-size-label);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.wg_shellToc__list {
|
|
27
|
+
margin: 0 0 0 var(--app-space-tree-inset);
|
|
28
|
+
padding: 0;
|
|
29
|
+
list-style: none;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.wg_shellToc__link {
|
|
33
|
+
/* 가로 가지는 링크 첫 줄 기준 · 여러 줄 제목에서도 연결 위치 유지 */
|
|
34
|
+
position: relative;
|
|
35
|
+
display: block;
|
|
36
|
+
padding: var(--app-space-tree-row) 0 var(--app-space-tree-row) calc(var(--app-space-tree-indent) + var(--app-space-inline));
|
|
37
|
+
color: var(--app-color-text-muted);
|
|
38
|
+
font-size: var(--app-font-size-dense);
|
|
39
|
+
line-height: var(--app-line-height-tight);
|
|
40
|
+
text-decoration: none;
|
|
41
|
+
|
|
42
|
+
&::before {
|
|
43
|
+
position: absolute;
|
|
44
|
+
top: calc(0.5lh + var(--app-space-tree-row));
|
|
45
|
+
left: 0;
|
|
46
|
+
width: var(--app-space-tree-indent);
|
|
47
|
+
border-top: 1px solid var(--app-color-border-soft);
|
|
48
|
+
content: "";
|
|
49
|
+
pointer-events: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&:where(:hover) {
|
|
53
|
+
color: var(--app-color-text-strong);
|
|
54
|
+
text-decoration: underline;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&:where(:hover)::before {
|
|
58
|
+
border-top-color: currentcolor;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* 박스 대신 hover와 같은 진한 글·밑줄·가지선으로 키보드 위치 표시 */
|
|
62
|
+
&:where(:focus-visible) {
|
|
63
|
+
outline: none;
|
|
64
|
+
color: var(--app-color-text-strong);
|
|
65
|
+
text-decoration: underline;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
&:where(:focus-visible)::before {
|
|
69
|
+
border-top-color: currentcolor;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.wg_shellToc__link--active {
|
|
74
|
+
color: var(--app-color-text-strong);
|
|
75
|
+
font-weight: var(--app-font-weight-active);
|
|
76
|
+
|
|
77
|
+
&::before {
|
|
78
|
+
border-top-color: currentcolor;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.wg_shellToc__item {
|
|
83
|
+
/* 하위 목록의 margin을 포함해 다음 항목까지 줄기 연결 */
|
|
84
|
+
display: flow-root;
|
|
85
|
+
|
|
86
|
+
/* 세로 줄기는 항목 전체 기준 · 중간 항목의 소제목 옆에서도 연결 */
|
|
87
|
+
position: relative;
|
|
88
|
+
|
|
89
|
+
&::before {
|
|
90
|
+
position: absolute;
|
|
91
|
+
top: 0;
|
|
92
|
+
bottom: 0;
|
|
93
|
+
left: 0;
|
|
94
|
+
border-left: 1px solid var(--app-color-border-soft);
|
|
95
|
+
content: "";
|
|
96
|
+
pointer-events: none;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
&:where(:last-child)::before {
|
|
100
|
+
bottom: auto;
|
|
101
|
+
height: calc(0.5lh + var(--app-space-tree-row));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* hover·키보드 포커스의 도착점 · 첫 줄 아래는 기본 줄기 유지 */
|
|
105
|
+
&::after {
|
|
106
|
+
position: absolute;
|
|
107
|
+
top: 0;
|
|
108
|
+
left: 0;
|
|
109
|
+
height: calc(0.5lh + var(--app-space-tree-row));
|
|
110
|
+
border-left: 1px solid transparent;
|
|
111
|
+
content: "";
|
|
112
|
+
pointer-events: none;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
&:where(:hover)::after {
|
|
116
|
+
border-left-color: var(--app-color-text-strong);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
&:where(:has(:focus-visible))::after {
|
|
120
|
+
border-left-color: var(--app-color-text-strong);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* 뒤 항목까지의 세로 경로 · 같은 목록의 형제 안에서만 연결 */
|
|
124
|
+
&:where(:has(~ .wg_shellToc__item:hover))::before {
|
|
125
|
+
border-left-color: var(--app-color-text-strong);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
&:where(:has(~ .wg_shellToc__item :focus-visible))::before {
|
|
129
|
+
border-left-color: var(--app-color-text-strong);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* 하위 제목을 탐색할 때 상위 절의 가지도 연결 */
|
|
133
|
+
&:where(:hover) > .wg_shellToc__link::before {
|
|
134
|
+
border-top-color: var(--app-color-text-strong);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
&:where(:has(:focus-visible)) > .wg_shellToc__link::before {
|
|
138
|
+
border-top-color: var(--app-color-text-strong);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.wg_shellToc__item--trail {
|
|
143
|
+
&::before {
|
|
144
|
+
border-left-color: var(--app-color-text-strong);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.wg_shellToc__item--current {
|
|
149
|
+
&::after {
|
|
150
|
+
border-left-color: var(--app-color-text-strong);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.wg_shellToc__sub {
|
|
155
|
+
margin: var(--app-space-tree-row) 0 4px var(--app-space-tree-indent);
|
|
156
|
+
padding: 0;
|
|
157
|
+
list-style: none;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.wg_shellToc__subItem {
|
|
161
|
+
/* 하위 줄기는 소제목 항목 기준 · 마지막 소제목 첫 줄에서 종료 */
|
|
162
|
+
position: relative;
|
|
163
|
+
|
|
164
|
+
&::before {
|
|
165
|
+
position: absolute;
|
|
166
|
+
top: 0;
|
|
167
|
+
bottom: 0;
|
|
168
|
+
left: 0;
|
|
169
|
+
border-left: 1px solid var(--app-color-border-soft);
|
|
170
|
+
content: "";
|
|
171
|
+
pointer-events: none;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
&:where(:last-child)::before {
|
|
175
|
+
bottom: auto;
|
|
176
|
+
height: calc(0.5lh + var(--app-space-tree-row));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* hover·키보드 포커스의 도착점 · 첫 줄 아래는 기본 줄기 유지 */
|
|
180
|
+
&::after {
|
|
181
|
+
position: absolute;
|
|
182
|
+
top: 0;
|
|
183
|
+
left: 0;
|
|
184
|
+
height: calc(0.5lh + var(--app-space-tree-row));
|
|
185
|
+
border-left: 1px solid transparent;
|
|
186
|
+
content: "";
|
|
187
|
+
pointer-events: none;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
&:where(:hover)::after {
|
|
191
|
+
border-left-color: var(--app-color-text-strong);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
&:where(:has(:focus-visible))::after {
|
|
195
|
+
border-left-color: var(--app-color-text-strong);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* 뒤 항목까지의 세로 경로 · 같은 목록의 형제 안에서만 연결 */
|
|
199
|
+
&:where(:has(~ .wg_shellToc__subItem:hover))::before {
|
|
200
|
+
border-left-color: var(--app-color-text-strong);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
&:where(:has(~ .wg_shellToc__subItem :focus-visible))::before {
|
|
204
|
+
border-left-color: var(--app-color-text-strong);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.wg_shellToc__subItem--trail {
|
|
209
|
+
&::before {
|
|
210
|
+
border-left-color: var(--app-color-text-strong);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.wg_shellToc__subItem--current {
|
|
215
|
+
&::after {
|
|
216
|
+
border-left-color: var(--app-color-text-strong);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.wg_shellToc__subLink {
|
|
221
|
+
/* 하위 가지도 링크 첫 줄 기준 · 줄바꿈된 제목 옆으로 선이 늘어나지 않음 */
|
|
222
|
+
position: relative;
|
|
223
|
+
display: block;
|
|
224
|
+
padding: var(--app-space-tree-row) 0 var(--app-space-tree-row) calc(var(--app-space-tree-indent) + var(--app-space-inline));
|
|
225
|
+
color: var(--app-color-text-muted);
|
|
226
|
+
font-size: var(--app-font-size-detail);
|
|
227
|
+
line-height: var(--app-line-height-tight);
|
|
228
|
+
text-decoration: none;
|
|
229
|
+
|
|
230
|
+
&::before {
|
|
231
|
+
position: absolute;
|
|
232
|
+
top: calc(0.5lh + var(--app-space-tree-row));
|
|
233
|
+
left: 0;
|
|
234
|
+
width: var(--app-space-tree-indent);
|
|
235
|
+
border-top: 1px solid var(--app-color-border-soft);
|
|
236
|
+
content: "";
|
|
237
|
+
pointer-events: none;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
&:where(:hover) {
|
|
241
|
+
color: var(--app-color-text-strong);
|
|
242
|
+
text-decoration: underline;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
&:where(:hover)::before {
|
|
246
|
+
border-top-color: currentcolor;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/* 상위 목차와 같은 키보드 표현 */
|
|
250
|
+
&:where(:focus-visible) {
|
|
251
|
+
outline: none;
|
|
252
|
+
color: var(--app-color-text-strong);
|
|
253
|
+
text-decoration: underline;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
&:where(:focus-visible)::before {
|
|
257
|
+
border-top-color: currentcolor;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.wg_shellToc__subLink--active {
|
|
262
|
+
color: var(--app-color-text-strong);
|
|
263
|
+
font-weight: var(--app-font-weight-active);
|
|
264
|
+
|
|
265
|
+
&::before {
|
|
266
|
+
border-top-color: currentcolor;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import {Fragment} from "react";
|
|
3
|
+
import type {TocGroup} from "@/component/widget/shell/_type/toc-group";
|
|
4
|
+
import {copy_nav_toc_label} from "@/constant/copy";
|
|
5
|
+
import "./_wg-shell-toc.css";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 문서 탐색 아래의 현재 문서 목차 · client.ts에서 읽는 위치 표시
|
|
9
|
+
*/
|
|
10
|
+
export interface WgShellTocProps {
|
|
11
|
+
/**
|
|
12
|
+
* 본문 순서의 가름·절·소제목 · 전체 펼침
|
|
13
|
+
*/
|
|
14
|
+
groups: TocGroup[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const WgShellToc = (props: WgShellTocProps) => {
|
|
18
|
+
return (
|
|
19
|
+
<nav className={clsx("wg_shellToc__root")} aria-label={copy_nav_toc_label}>
|
|
20
|
+
<div className={clsx("wg_shellToc__label")}>{copy_nav_toc_label}</div>
|
|
21
|
+
{/**
|
|
22
|
+
* 가름별 제목 이동 · 작성한 제목을 본문과 동일하게 표시
|
|
23
|
+
*/}
|
|
24
|
+
{props.groups.map((group) => (
|
|
25
|
+
<Fragment key={group.sections[0].heading.slug}>
|
|
26
|
+
{group.part !== undefined && <div className={clsx("wg_shellToc__group")}>{group.part}</div>}
|
|
27
|
+
{/**
|
|
28
|
+
* 현재 위치와 무관하게 모든 소제목 표시
|
|
29
|
+
*/}
|
|
30
|
+
<ul className={clsx("wg_shellToc__list")}>
|
|
31
|
+
{group.sections.map((section) => (
|
|
32
|
+
<li className={clsx("wg_shellToc__item")} key={section.heading.slug}>
|
|
33
|
+
<a className={clsx("wg_shellToc__link")} href={`#${section.heading.slug}`} data-toc-link="">
|
|
34
|
+
{section.heading.text}
|
|
35
|
+
</a>
|
|
36
|
+
{/**
|
|
37
|
+
* 소제목의 들여쓰기 · JavaScript 없이도 제목 이동 가능
|
|
38
|
+
*/}
|
|
39
|
+
{section.subs.length > 0 && (
|
|
40
|
+
<ul className={clsx("wg_shellToc__sub")}>
|
|
41
|
+
{section.subs.map((sub) => (
|
|
42
|
+
<li className={clsx("wg_shellToc__subItem")} key={sub.heading.slug}>
|
|
43
|
+
<a className={clsx("wg_shellToc__subLink")} href={`#${sub.heading.slug}`} data-toc-sub-link="">
|
|
44
|
+
{sub.heading.text}
|
|
45
|
+
</a>
|
|
46
|
+
</li>
|
|
47
|
+
))}
|
|
48
|
+
</ul>
|
|
49
|
+
)}
|
|
50
|
+
</li>
|
|
51
|
+
))}
|
|
52
|
+
</ul>
|
|
53
|
+
</Fragment>
|
|
54
|
+
))}
|
|
55
|
+
</nav>
|
|
56
|
+
);
|
|
57
|
+
};
|