for-humanity 0.4.3 → 0.5.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.
Files changed (79) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +5 -5
  3. package/dist/browser.js +39 -0
  4. package/dist/cli.css +372 -299
  5. package/dist/cli.js +1125 -301
  6. package/package.json +8 -11
  7. package/src/component/widget/{shell → cursor-face}/_constant/cursor-face.ts +5 -0
  8. package/src/component/widget/cursor-face/wg-cursor-face.css +15 -0
  9. package/src/component/widget/cursor-face/wg-cursor-face.tsx +153 -0
  10. package/src/component/widget/navigation/_constant/navigation-data-schema.ts +35 -0
  11. package/src/component/widget/navigation/_constant/navigation.ts +9 -0
  12. package/src/component/widget/navigation/_function/restore-navigation-scroll.ts +59 -0
  13. package/src/{content → component/widget/navigation/_function}/to-doc-groups/_to-doc-branches.ts +2 -2
  14. package/src/{content → component/widget/navigation/_function}/to-doc-groups/_to-doc-group-branches.ts +3 -3
  15. package/src/{content → component/widget/navigation/_function}/to-doc-groups/to-doc-groups.ts +1 -1
  16. package/src/component/widget/navigation/_function/to-navigation-branch-id.ts +6 -0
  17. package/src/component/widget/navigation/_function/to-navigation-data/_to-navigation-document.ts +14 -0
  18. package/src/component/widget/navigation/_function/to-navigation-data/_to-navigation-group.ts +14 -0
  19. package/src/component/widget/navigation/_function/to-navigation-data/to-navigation-data.ts +25 -0
  20. package/src/component/widget/navigation/_function/to-navigation-json.ts +8 -0
  21. package/src/component/widget/{shell → navigation}/_function/to-toc-groups.ts +2 -2
  22. package/src/{type → component/widget/navigation/_type}/doc-group.ts +1 -1
  23. package/src/component/widget/navigation/_type/navigation-data.ts +83 -0
  24. package/src/component/widget/navigation/_type/navigation-focus-snapshot.ts +21 -0
  25. package/src/component/widget/navigation/_wg-navigation-branch-toggle.css +28 -0
  26. package/src/component/widget/navigation/_wg-navigation-branch-toggle.tsx +48 -0
  27. package/src/component/widget/{shell/_wg-shell-nav-list.css → navigation/_wg-navigation-nav-list.css} +24 -16
  28. package/src/component/widget/navigation/_wg-navigation-nav-list.tsx +106 -0
  29. package/src/component/widget/{shell/_wg-shell-nav.css → navigation/_wg-navigation-nav.css} +9 -3
  30. package/src/component/widget/navigation/_wg-navigation-nav.tsx +43 -0
  31. package/src/component/widget/navigation/_wg-navigation-scroll.tsx +117 -0
  32. package/src/component/widget/{shell/_wg-shell-toc.css → navigation/_wg-navigation-toc.css} +43 -26
  33. package/src/component/widget/navigation/_wg-navigation-toc.tsx +155 -0
  34. package/src/component/widget/navigation/wg-navigation.css +282 -0
  35. package/src/component/widget/navigation/wg-navigation.tsx +479 -0
  36. package/src/component/widget/prose/_function/rehype-sections/rehype-sections.ts +1 -1
  37. package/src/component/widget/shell/wg-shell.css +13 -309
  38. package/src/component/widget/shell/wg-shell.tsx +16 -75
  39. package/src/component/widget/shell-controls/wg-shell-controls.css +4 -0
  40. package/src/component/widget/shell-controls/wg-shell-controls.tsx +170 -0
  41. package/src/constant/asset.ts +0 -5
  42. package/src/entry/browser/browser.tsx +22 -0
  43. package/src/{app.tsx → entry/cli/_function/create-app.tsx} +6 -6
  44. package/src/{content → entry/cli/_function/create-processor}/create-processor.ts +3 -3
  45. package/src/{content → entry/cli/_function}/read-docs.ts +1 -1
  46. package/src/{content → entry/cli/_function}/read-home.ts +1 -1
  47. package/src/{content/read-docs.test.ts → entry/cli/cli.test.ts} +105 -30
  48. package/src/{cli.ts → entry/cli/cli.ts} +10 -11
  49. package/src/store/navigation/_constant/tree.ts +6 -0
  50. package/src/store/navigation/create-navigation-stores.test.ts +92 -0
  51. package/src/store/navigation/create-navigation-stores.ts +73 -0
  52. package/src/store/navigation/navigation-state.ts +46 -0
  53. package/src/store/navigation/navigation-storage.ts +14 -0
  54. package/src/store/navigation/to-navigation-scroll-state.ts +42 -0
  55. package/src/store/navigation/to-navigation-tree-state.ts +19 -0
  56. package/src/store/navigation/use-navigation-tree-store.ts +12 -0
  57. package/src/style/token.css +4 -2
  58. package/src/type/doc-content.ts +1 -1
  59. package/src/type/doc-file-data.ts +1 -1
  60. package/src/{component/widget/shell/_type → type}/doc-outline.ts +1 -1
  61. package/src/type/site-assets.ts +2 -2
  62. package/dist/client.js +0 -6
  63. package/src/client.ts +0 -335
  64. package/src/component/widget/shell/_constant/navigation.ts +0 -9
  65. package/src/component/widget/shell/_function/bind-mobile-navigation.ts +0 -140
  66. package/src/component/widget/shell/_function/bind-navigation-scroll.ts +0 -123
  67. package/src/component/widget/shell/_wg-shell-nav-list.tsx +0 -87
  68. package/src/component/widget/shell/_wg-shell-nav.tsx +0 -49
  69. package/src/component/widget/shell/_wg-shell-toc.tsx +0 -57
  70. /package/src/{constant → component/widget/navigation/_constant}/locale.ts +0 -0
  71. /package/src/component/widget/{shell → navigation}/_constant/reading-line.ts +0 -0
  72. /package/src/{type → component/widget/navigation/_type}/doc-branch.ts +0 -0
  73. /package/src/component/widget/{shell → navigation}/_type/toc-group.ts +0 -0
  74. /package/src/{constant → entry/cli/_constant}/cli.ts +0 -0
  75. /package/src/{dev.ts → entry/cli/_function/create-dev-app.ts} +0 -0
  76. /package/src/{content/rehype-assets.ts → entry/cli/_function/create-processor/_rehype-assets.ts} +0 -0
  77. /package/src/{content/rehype-heading-ids.ts → entry/cli/_function/create-processor/_rehype-heading-ids.ts} +0 -0
  78. /package/src/{content/remark-report.ts → entry/cli/_function/create-processor/_remark-report.ts} +0 -0
  79. /package/src/{component/widget/prose/_type → type}/doc-section.ts +0 -0
@@ -1,123 +0,0 @@
1
- import {navigation_mobile_query, navigation_scroll_storage_key} from "@/component/widget/shell/_constant/navigation";
2
-
3
- /**
4
- * 문서 이동·새로고침에서 공유 탐색의 위치 유지 · 본문 스크롤과 독립
5
- * 저장소 실패는 기본 탐색 유지, 문서 목록 변경은 이전 위치를 사용하지 않음
6
- */
7
- export const bindNavigationScroll = () => {
8
- const navigation = document.querySelector<HTMLElement>("[data-navigation]");
9
- const sidebar = document.querySelector<HTMLElement>(".wg_shell__sidebar");
10
- const dialog = document.querySelector<HTMLDialogElement>("[data-navigation-drawer]");
11
- const openButton = document.querySelector<HTMLButtonElement>("[data-navigation-open]");
12
-
13
- if (!navigation || !sidebar || !dialog || !openButton) {
14
- return;
15
- }
16
-
17
- const mobile = matchMedia(navigation_mobile_query);
18
- const layout = {mobile: mobile.matches};
19
- // 목차와 현재 상태는 페이지마다 바뀜 · 공통 문서 링크의 순서로 저장 위치의 유효성 판단
20
- const signature = [...navigation.querySelectorAll<HTMLAnchorElement>(".wg_shellNav__root a[href]")].map((link) => `${link.pathname}:${link.textContent}`).join("\n");
21
- const positions = new Map<HTMLElement, number>();
22
- const storageKeys = new Map<HTMLElement, string>([
23
- [sidebar, `${navigation_scroll_storage_key}:desktop`],
24
- [dialog, `${navigation_scroll_storage_key}:drawer`],
25
- ]);
26
- const userInput = new AbortController();
27
-
28
- for (const [port, key] of storageKeys) {
29
- try {
30
- const value = sessionStorage.getItem(key);
31
-
32
- if (value !== null) {
33
- const stored: unknown = JSON.parse(value);
34
-
35
- if (
36
- typeof stored === "object" &&
37
- stored !== null &&
38
- "navigation" in stored &&
39
- stored.navigation === signature &&
40
- "top" in stored &&
41
- typeof stored.top === "number" &&
42
- Number.isFinite(stored.top) &&
43
- stored.top >= 0
44
- ) {
45
- positions.set(port, stored.top);
46
- }
47
- }
48
- } catch {
49
- // 차단되거나 손상된 저장소는 복원만 생략 · 스크롤과 기본 링크 이동 유지
50
- }
51
-
52
- for (const type of ["wheel", "touchstart", "pointerdown", "keydown"]) {
53
- port.addEventListener(type, () => userInput.abort(), {once: true, passive: true});
54
- }
55
- }
56
- const initialPositions = new Map(positions);
57
-
58
- /**
59
- * 네이티브 스크롤 범위로 복원 · 닫힌 드로어의 0 좌표는 복원하지 않음
60
- */
61
- const restoreScroll = () => {
62
- layout.mobile = mobile.matches;
63
- const port = mobile.matches ? dialog : sidebar;
64
- const top = positions.get(port);
65
-
66
- if (top === undefined || (mobile.matches && !dialog.open)) {
67
- return;
68
- }
69
-
70
- port.scrollTop = top;
71
- };
72
-
73
- /**
74
- * 드로어 닫기 이전 클릭·현재 스크롤·페이지 이탈에서 마지막 탐색 위치 저장
75
- */
76
- const saveScroll = (event: Event) => {
77
- const port = mobile.matches ? dialog : sidebar;
78
- const key = storageKeys.get(port);
79
-
80
- // 반응형 전환의 숨김·닫기 스크롤은 사용자 위치가 아님 · 활성 포트만 저장
81
- if (layout.mobile !== mobile.matches || (event.type === "scroll" && event.currentTarget !== port) || key === undefined || (mobile.matches && !dialog.open)) {
82
- return;
83
- }
84
-
85
- positions.set(port, port.scrollTop);
86
-
87
- try {
88
- sessionStorage.setItem(key, JSON.stringify({navigation: signature, top: port.scrollTop}));
89
- } catch {
90
- // 저장 실패도 같은 페이지의 드로어 재열기와 반응형 위치 복원은 유지
91
- }
92
- };
93
-
94
- /**
95
- * 글꼴로 탐색 높이가 달라진 경우 한 번만 재보정 · 사용자 입력이 먼저면 유지
96
- */
97
- const settleScroll = async () => {
98
- await document.fonts.ready;
99
-
100
- if (!userInput.signal.aborted) {
101
- const port = mobile.matches ? dialog : sidebar;
102
- const top = initialPositions.get(port);
103
-
104
- if (top !== undefined && (!mobile.matches || dialog.open)) {
105
- port.scrollTop = top;
106
- }
107
- }
108
- };
109
-
110
- sidebar.addEventListener("scroll", saveScroll, {passive: true});
111
- dialog.addEventListener("scroll", saveScroll, {passive: true});
112
- navigation.addEventListener("click", saveScroll, {capture: true});
113
- openButton.addEventListener("click", restoreScroll);
114
- mobile.addEventListener("change", restoreScroll);
115
- addEventListener("pagehide", saveScroll);
116
- restoreScroll();
117
-
118
- if (document.readyState === "complete") {
119
- settleScroll();
120
- } else {
121
- addEventListener("load", settleScroll, {once: true});
122
- }
123
- };
@@ -1,87 +0,0 @@
1
- import clsx from "clsx";
2
- import {Fragment} from "react";
3
- import type {Doc} from "@/type/doc";
4
- import type {DocGroup} from "@/type/doc-group";
5
- import "./_wg-shell-nav-list.css";
6
-
7
- /**
8
- * 한 단계의 문서 목록과 하위 묶음 · 재귀에서도 같은 탐색 표현 유지
9
- */
10
- export interface WgShellNavListProps {
11
- /**
12
- * 현재 단계의 문서와 하위 묶음
13
- */
14
- group: DocGroup;
15
- /**
16
- * 현재 문서 · 조상 묶음의 경로까지 표시
17
- */
18
- currentDoc?: Doc;
19
- }
20
-
21
- export const WgShellNavList = (props: WgShellNavListProps) => {
22
- const currentAncestors = new Set(props.currentDoc?.ancestors);
23
- const entries = [
24
- ...props.group.docs.map((doc) => {
25
- const active = doc.id === props.currentDoc?.id;
26
- return {kind: "document" as const, key: `doc:${doc.id}`, doc, active, current: active || currentAncestors.has(doc.id)};
27
- }),
28
- ...props.group.groups.map((group) => ({
29
- kind: "group" as const,
30
- key: `group:${JSON.stringify(group.path)}`,
31
- group,
32
- current: group.path.every((name, index) => name === props.currentDoc?.data.group[index]),
33
- })),
34
- ];
35
- const currentIndex = entries.findIndex((entry) => entry.current);
36
-
37
- return (
38
- <ul className={clsx("wg_shellNavList__root")} aria-label={props.group.name}>
39
- {/**
40
- * 현재 경로 앞의 줄기와 도착 가지 · 문서 링크는 원래 파일 URL 사용
41
- */}
42
- {entries.map((entry, index) => (
43
- <li
44
- className={clsx("wg_shellNavList__item", {
45
- "wg_shellNavList__item--trail": index < currentIndex,
46
- "wg_shellNavList__item--current": entry.current,
47
- })}
48
- key={entry.key}
49
- >
50
- {/**
51
- * 문서 링크 · 부모도 독립 페이지, 현재 한 문서에만 페이지 상태 부여
52
- */}
53
- {entry.kind === "document" && (
54
- <Fragment>
55
- <a
56
- className={clsx("wg_shellNavList__link", {"wg_shellNavList__link--active": entry.active})}
57
- href={`/${entry.doc.id}/`}
58
- title={entry.doc.data.label}
59
- aria-current={entry.active ? "page" : undefined}
60
- >
61
- {entry.doc.data.name}
62
- </a>
63
- {/**
64
- * 하위 문서 · 부모 아래에서도 기존 목록의 들여쓰기와 키보드 이동 유지
65
- */}
66
- {entry.doc.children !== undefined && (
67
- <WgShellNavList
68
- group={{name: entry.doc.data.name, path: entry.doc.data.group, docs: entry.doc.children, groups: []}}
69
- currentDoc={props.currentDoc}
70
- />
71
- )}
72
- </Fragment>
73
- )}
74
- {/**
75
- * 하위 묶음 · 같은 목록을 재귀로 이어 깊이에 따라 들여쓰기
76
- */}
77
- {entry.kind === "group" && (
78
- <Fragment>
79
- <span className={clsx("wg_shellNavList__branch")}>{entry.group.name}</span>
80
- <WgShellNavList group={entry.group} currentDoc={props.currentDoc} />
81
- </Fragment>
82
- )}
83
- </li>
84
- ))}
85
- </ul>
86
- );
87
- };
@@ -1,49 +0,0 @@
1
- import clsx from "clsx";
2
- import {WgShellNavList} from "@/component/widget/shell/_wg-shell-nav-list";
3
- import {copy_nav_aria_label} from "@/constant/copy";
4
- import {toDocGroups} from "@/content/to-doc-groups/to-doc-groups";
5
- import type {Doc} from "@/type/doc";
6
- import type {SiteConfig} from "@/type/site-config";
7
- import "./_wg-shell-nav.css";
8
-
9
- /**
10
- * 서버 사이드바 입력 · 읽는 순서의 문서 묶음
11
- */
12
- export interface WgShellNavProps {
13
- /**
14
- * 문서 묶음 순서
15
- */
16
- site: SiteConfig;
17
- /**
18
- * 전체 문서 목록
19
- */
20
- docs: Doc[];
21
- /**
22
- * 현재 문서 id · 첫 화면 생략
23
- */
24
- current?: string;
25
- }
26
-
27
- export const WgShellNav = (props: WgShellNavProps) => {
28
- const docGroups = toDocGroups({docs: props.docs, navigation: props.site.navigation});
29
- const currentDoc = props.docs.find((doc) => doc.id === props.current);
30
-
31
- return (
32
- <nav className={clsx("wg_shellNav__root")} aria-label={copy_nav_aria_label}>
33
- {/**
34
- * 문서 이동 · 독자 목적별 묶음
35
- */}
36
- <div className={clsx("wg_shellNav__docs")}>
37
- {/**
38
- * 묶음 이름과 독립 문서 · 제목이 링크의 접근 가능한 이름
39
- */}
40
- {docGroups.map((group) => (
41
- <section className={clsx("wg_shellNav__docGroup")} key={group.name} aria-label={group.name}>
42
- <div className={clsx("wg_shellNav__group")}>{group.name}</div>
43
- <WgShellNavList group={group} currentDoc={currentDoc} />
44
- </section>
45
- ))}
46
- </div>
47
- </nav>
48
- );
49
- };
@@ -1,57 +0,0 @@
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
- };
File without changes