boltdocs 1.3.0 → 1.3.2

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 (103) hide show
  1. package/dist/{cache-EHR7SXRU.mjs → cache-GQHF6BXI.mjs} +1 -1
  2. package/dist/{chunk-GSYECEZY.mjs → chunk-CYBWLFOG.mjs} +5 -1
  3. package/dist/node/index.js +36 -20
  4. package/dist/node/index.mjs +34 -22
  5. package/package.json +1 -1
  6. package/src/client/app/index.tsx +344 -344
  7. package/src/client/app/preload.tsx +56 -56
  8. package/src/client/index.ts +40 -40
  9. package/src/client/ssr.tsx +51 -51
  10. package/src/client/theme/components/CodeBlock/CodeBlock.tsx +76 -76
  11. package/src/client/theme/components/CodeBlock/index.ts +1 -1
  12. package/src/client/theme/components/PackageManagerTabs/PackageManagerTabs.tsx +154 -154
  13. package/src/client/theme/components/PackageManagerTabs/index.ts +1 -1
  14. package/src/client/theme/components/PackageManagerTabs/pkg-tabs.css +64 -64
  15. package/src/client/theme/components/Playground/Playground.tsx +124 -124
  16. package/src/client/theme/components/Playground/index.ts +1 -1
  17. package/src/client/theme/components/Playground/playground.css +168 -168
  18. package/src/client/theme/components/Video/Video.tsx +84 -84
  19. package/src/client/theme/components/Video/index.ts +1 -1
  20. package/src/client/theme/components/Video/video.css +41 -41
  21. package/src/client/theme/components/mdx/Admonition.tsx +80 -80
  22. package/src/client/theme/components/mdx/Badge.tsx +31 -31
  23. package/src/client/theme/components/mdx/Button.tsx +50 -50
  24. package/src/client/theme/components/mdx/Card.tsx +80 -80
  25. package/src/client/theme/components/mdx/List.tsx +57 -57
  26. package/src/client/theme/components/mdx/Tabs.tsx +94 -94
  27. package/src/client/theme/components/mdx/index.ts +18 -18
  28. package/src/client/theme/components/mdx/mdx-components.css +424 -424
  29. package/src/client/theme/icons/bun.tsx +62 -62
  30. package/src/client/theme/icons/deno.tsx +20 -20
  31. package/src/client/theme/icons/discord.tsx +12 -12
  32. package/src/client/theme/icons/github.tsx +15 -15
  33. package/src/client/theme/icons/npm.tsx +13 -13
  34. package/src/client/theme/icons/pnpm.tsx +72 -72
  35. package/src/client/theme/icons/twitter.tsx +12 -12
  36. package/src/client/theme/styles/markdown.css +343 -343
  37. package/src/client/theme/styles/variables.css +162 -162
  38. package/src/client/theme/styles.css +37 -37
  39. package/src/client/theme/ui/BackgroundGradient/BackgroundGradient.tsx +10 -10
  40. package/src/client/theme/ui/BackgroundGradient/index.ts +1 -1
  41. package/src/client/theme/ui/Breadcrumbs/Breadcrumbs.tsx +68 -68
  42. package/src/client/theme/ui/Breadcrumbs/index.ts +1 -1
  43. package/src/client/theme/ui/Footer/footer.css +32 -32
  44. package/src/client/theme/ui/Head/Head.tsx +69 -69
  45. package/src/client/theme/ui/Head/index.ts +1 -1
  46. package/src/client/theme/ui/LanguageSwitcher/LanguageSwitcher.tsx +125 -125
  47. package/src/client/theme/ui/LanguageSwitcher/index.ts +1 -1
  48. package/src/client/theme/ui/LanguageSwitcher/language-switcher.css +98 -98
  49. package/src/client/theme/ui/Layout/Layout.tsx +202 -202
  50. package/src/client/theme/ui/Layout/base.css +76 -76
  51. package/src/client/theme/ui/Layout/index.ts +2 -2
  52. package/src/client/theme/ui/Layout/pagination.css +72 -72
  53. package/src/client/theme/ui/Layout/responsive.css +36 -36
  54. package/src/client/theme/ui/Link/Link.tsx +254 -254
  55. package/src/client/theme/ui/Link/index.ts +2 -2
  56. package/src/client/theme/ui/Loading/Loading.tsx +10 -10
  57. package/src/client/theme/ui/Loading/index.ts +1 -1
  58. package/src/client/theme/ui/Loading/loading.css +30 -30
  59. package/src/client/theme/ui/Navbar/GithubStars.tsx +27 -27
  60. package/src/client/theme/ui/Navbar/Navbar.tsx +145 -145
  61. package/src/client/theme/ui/Navbar/index.ts +2 -2
  62. package/src/client/theme/ui/Navbar/navbar.css +233 -233
  63. package/src/client/theme/ui/NotFound/NotFound.tsx +19 -19
  64. package/src/client/theme/ui/NotFound/index.ts +1 -1
  65. package/src/client/theme/ui/NotFound/not-found.css +64 -64
  66. package/src/client/theme/ui/OnThisPage/OnThisPage.tsx +235 -235
  67. package/src/client/theme/ui/OnThisPage/index.ts +1 -1
  68. package/src/client/theme/ui/OnThisPage/toc.css +132 -132
  69. package/src/client/theme/ui/PoweredBy/PoweredBy.tsx +18 -18
  70. package/src/client/theme/ui/PoweredBy/index.ts +1 -1
  71. package/src/client/theme/ui/PoweredBy/powered-by.css +76 -76
  72. package/src/client/theme/ui/SearchDialog/SearchDialog.tsx +199 -199
  73. package/src/client/theme/ui/SearchDialog/index.ts +1 -1
  74. package/src/client/theme/ui/SearchDialog/search.css +152 -152
  75. package/src/client/theme/ui/Sidebar/Sidebar.tsx +204 -204
  76. package/src/client/theme/ui/Sidebar/index.ts +1 -1
  77. package/src/client/theme/ui/Sidebar/sidebar.css +236 -236
  78. package/src/client/theme/ui/ThemeToggle/ThemeToggle.tsx +69 -69
  79. package/src/client/theme/ui/ThemeToggle/index.ts +1 -1
  80. package/src/client/theme/ui/VersionSwitcher/VersionSwitcher.tsx +136 -136
  81. package/src/client/theme/ui/VersionSwitcher/index.ts +1 -1
  82. package/src/client/types.ts +50 -50
  83. package/src/client/utils.ts +26 -26
  84. package/src/node/cache.ts +408 -408
  85. package/src/node/config.ts +192 -192
  86. package/src/node/index.ts +21 -21
  87. package/src/node/mdx.ts +120 -120
  88. package/src/node/plugin/entry.ts +58 -58
  89. package/src/node/plugin/html.ts +55 -55
  90. package/src/node/plugin/index.ts +193 -193
  91. package/src/node/plugin/types.ts +11 -11
  92. package/src/node/routes/cache.ts +28 -28
  93. package/src/node/routes/index.ts +167 -167
  94. package/src/node/routes/parser.ts +153 -127
  95. package/src/node/routes/sorter.ts +42 -42
  96. package/src/node/routes/types.ts +49 -49
  97. package/src/node/ssg/index.ts +114 -114
  98. package/src/node/ssg/meta.ts +33 -34
  99. package/src/node/ssg/options.ts +13 -13
  100. package/src/node/ssg/sitemap.ts +55 -54
  101. package/src/node/utils.ts +145 -134
  102. package/tsconfig.json +20 -20
  103. package/tsup.config.ts +22 -22
@@ -1,235 +1,235 @@
1
- import React, { useEffect, useState, useRef, useCallback } from "react";
2
- import { useLocation } from "react-router-dom";
3
- import { Pencil, CircleHelp } from "lucide-react";
4
-
5
- interface TocHeading {
6
- id: string;
7
- text: string;
8
- level: number;
9
- }
10
-
11
- export function OnThisPage({
12
- headings = [],
13
- editLink,
14
- communityHelp,
15
- filePath,
16
- }: {
17
- headings?: TocHeading[];
18
- editLink?: string;
19
- communityHelp?: string;
20
- filePath?: string;
21
- }) {
22
- const [activeId, setActiveId] = useState<string>("");
23
- const [indicatorStyle, setIndicatorStyle] = useState<React.CSSProperties>({});
24
- const observerRef = useRef<IntersectionObserver | null>(null);
25
- const location = useLocation();
26
- const listRef = useRef<HTMLUListElement>(null);
27
-
28
- // Reset active ID when path changes
29
- useEffect(() => {
30
- if (headings.length > 0) {
31
- // Check if there's a hash in the URL
32
- const hash = window.location.hash.substring(1);
33
- if (hash && headings.some((h) => h.id === hash)) {
34
- setActiveId(hash);
35
- } else {
36
- setActiveId(headings[0].id);
37
- }
38
- }
39
- }, [location.pathname, headings]);
40
-
41
- // Update indicator position
42
- useEffect(() => {
43
- if (!activeId || !listRef.current) return;
44
-
45
- const activeElement = listRef.current.querySelector(
46
- `a[href="#${activeId}"]`,
47
- ) as HTMLElement;
48
-
49
- if (activeElement) {
50
- const { offsetTop, offsetHeight } = activeElement;
51
- setIndicatorStyle({
52
- transform: `translateY(${offsetTop}px)`,
53
- height: `${offsetHeight}px`,
54
- opacity: 1,
55
- });
56
- }
57
- }, [activeId, headings]);
58
-
59
- // IntersectionObserver for active heading tracking
60
- useEffect(() => {
61
- if (headings.length === 0) return;
62
-
63
- if (observerRef.current) {
64
- observerRef.current.disconnect();
65
- }
66
-
67
- const callback: IntersectionObserverCallback = (entries) => {
68
- // Find all entries that are intersecting
69
- const visibleEntries = entries.filter((entry) => entry.isIntersecting);
70
-
71
- if (visibleEntries.length > 0) {
72
- // If we have visible entries, find the one closest to the top of the viewport
73
- const closest = visibleEntries.reduce((prev, curr) => {
74
- return Math.abs(curr.boundingClientRect.top - 100) <
75
- Math.abs(prev.boundingClientRect.top - 100)
76
- ? curr
77
- : prev;
78
- });
79
- setActiveId(closest.target.id);
80
- }
81
- };
82
-
83
- observerRef.current = new IntersectionObserver(callback, {
84
- rootMargin: "-100px 0px -70% 0px",
85
- threshold: [0, 1],
86
- });
87
-
88
- const observeHeadings = () => {
89
- headings.forEach(({ id }) => {
90
- const el = document.getElementById(id);
91
- if (el) {
92
- observerRef.current!.observe(el);
93
- }
94
- });
95
- };
96
-
97
- // Initial observation
98
- observeHeadings();
99
-
100
- // Re-observe if content changes
101
- const timeoutId = setTimeout(observeHeadings, 1000);
102
-
103
- // Scroll listener to detect bottom of page
104
- const handleScroll = () => {
105
- const scrollPosition = window.innerHeight + window.pageYOffset;
106
- const bodyHeight = document.documentElement.scrollHeight;
107
-
108
- // If we're within 50px of the bottom, activate the last heading
109
- if (scrollPosition >= bodyHeight - 50) {
110
- setActiveId(headings[headings.length - 1].id);
111
- }
112
- };
113
-
114
- window.addEventListener("scroll", handleScroll, { passive: true });
115
-
116
- return () => {
117
- observerRef.current?.disconnect();
118
- clearTimeout(timeoutId);
119
- window.removeEventListener("scroll", handleScroll);
120
- };
121
- }, [headings, location.pathname]);
122
-
123
- // Autoscroll TOC list when activeId changes
124
- useEffect(() => {
125
- if (!activeId || !listRef.current) return;
126
-
127
- const activeLink = listRef.current.querySelector(
128
- `a[href="#${activeId}"]`,
129
- ) as HTMLElement;
130
-
131
- if (activeLink) {
132
- const container = listRef.current.closest(
133
- ".boltdocs-on-this-page",
134
- ) as HTMLElement;
135
- if (!container) return;
136
-
137
- const linkRect = activeLink.getBoundingClientRect();
138
- const containerRect = container.getBoundingClientRect();
139
-
140
- const isVisible =
141
- linkRect.top >= containerRect.top &&
142
- linkRect.bottom <= containerRect.bottom;
143
-
144
- if (!isVisible) {
145
- activeLink.scrollIntoView({
146
- behavior: "smooth",
147
- block: "nearest",
148
- });
149
- }
150
- }
151
- }, [activeId]);
152
-
153
- const handleClick = useCallback(
154
- (e: React.MouseEvent<HTMLAnchorElement>, id: string) => {
155
- e.preventDefault();
156
- const el = document.getElementById(id);
157
- if (el) {
158
- const offset = 80;
159
- const bodyRect = document.body.getBoundingClientRect().top;
160
- const elementRect = el.getBoundingClientRect().top;
161
- const elementPosition = elementRect - bodyRect;
162
- const offsetPosition = elementPosition - offset;
163
-
164
- window.scrollTo({
165
- top: offsetPosition,
166
- behavior: "smooth",
167
- });
168
-
169
- setActiveId(id);
170
- window.history.pushState(null, "", `#${id}`);
171
- }
172
- },
173
- [],
174
- );
175
-
176
- if (headings.length === 0) return null;
177
-
178
- return (
179
- <nav className="boltdocs-on-this-page" aria-label="Table of contents">
180
- <p className="on-this-page-title">On this page</p>
181
- <div className="on-this-page-container">
182
- <div className="toc-indicator" style={indicatorStyle} />
183
- <ul className="on-this-page-list" ref={listRef}>
184
- {headings.map((h) => (
185
- <li key={h.id} className={h.level === 3 ? "toc-indent" : ""}>
186
- <a
187
- href={`#${h.id}`}
188
- className={`toc-link ${activeId === h.id ? "active" : ""}`}
189
- aria-current={activeId === h.id ? "true" : undefined}
190
- onClick={(e) => handleClick(e, h.id)}
191
- >
192
- {h.text}
193
- </a>
194
- </li>
195
- ))}
196
- </ul>
197
- </div>
198
-
199
- {/* Need help? section */}
200
- {(editLink || communityHelp) && (
201
- <div className="toc-help">
202
- <p className="toc-help-title">Need help?</p>
203
- <ul className="toc-help-links">
204
- {editLink && filePath && (
205
- <li>
206
- <a
207
- href={editLink.replace(":path", filePath)}
208
- target="_blank"
209
- rel="noopener noreferrer"
210
- className="toc-help-link"
211
- >
212
- <Pencil size={16} />
213
- Edit this page
214
- </a>
215
- </li>
216
- )}
217
- {communityHelp && (
218
- <li>
219
- <a
220
- href={communityHelp}
221
- target="_blank"
222
- rel="noopener noreferrer"
223
- className="toc-help-link"
224
- >
225
- <CircleHelp size={16} />
226
- Community help
227
- </a>
228
- </li>
229
- )}
230
- </ul>
231
- </div>
232
- )}
233
- </nav>
234
- );
235
- }
1
+ import React, { useEffect, useState, useRef, useCallback } from "react";
2
+ import { useLocation } from "react-router-dom";
3
+ import { Pencil, CircleHelp } from "lucide-react";
4
+
5
+ interface TocHeading {
6
+ id: string;
7
+ text: string;
8
+ level: number;
9
+ }
10
+
11
+ export function OnThisPage({
12
+ headings = [],
13
+ editLink,
14
+ communityHelp,
15
+ filePath,
16
+ }: {
17
+ headings?: TocHeading[];
18
+ editLink?: string;
19
+ communityHelp?: string;
20
+ filePath?: string;
21
+ }) {
22
+ const [activeId, setActiveId] = useState<string>("");
23
+ const [indicatorStyle, setIndicatorStyle] = useState<React.CSSProperties>({});
24
+ const observerRef = useRef<IntersectionObserver | null>(null);
25
+ const location = useLocation();
26
+ const listRef = useRef<HTMLUListElement>(null);
27
+
28
+ // Reset active ID when path changes
29
+ useEffect(() => {
30
+ if (headings.length > 0) {
31
+ // Check if there's a hash in the URL
32
+ const hash = window.location.hash.substring(1);
33
+ if (hash && headings.some((h) => h.id === hash)) {
34
+ setActiveId(hash);
35
+ } else {
36
+ setActiveId(headings[0].id);
37
+ }
38
+ }
39
+ }, [location.pathname, headings]);
40
+
41
+ // Update indicator position
42
+ useEffect(() => {
43
+ if (!activeId || !listRef.current) return;
44
+
45
+ const activeElement = listRef.current.querySelector(
46
+ `a[href="#${activeId}"]`,
47
+ ) as HTMLElement;
48
+
49
+ if (activeElement) {
50
+ const { offsetTop, offsetHeight } = activeElement;
51
+ setIndicatorStyle({
52
+ transform: `translateY(${offsetTop}px)`,
53
+ height: `${offsetHeight}px`,
54
+ opacity: 1,
55
+ });
56
+ }
57
+ }, [activeId, headings]);
58
+
59
+ // IntersectionObserver for active heading tracking
60
+ useEffect(() => {
61
+ if (headings.length === 0) return;
62
+
63
+ if (observerRef.current) {
64
+ observerRef.current.disconnect();
65
+ }
66
+
67
+ const callback: IntersectionObserverCallback = (entries) => {
68
+ // Find all entries that are intersecting
69
+ const visibleEntries = entries.filter((entry) => entry.isIntersecting);
70
+
71
+ if (visibleEntries.length > 0) {
72
+ // If we have visible entries, find the one closest to the top of the viewport
73
+ const closest = visibleEntries.reduce((prev, curr) => {
74
+ return Math.abs(curr.boundingClientRect.top - 100) <
75
+ Math.abs(prev.boundingClientRect.top - 100)
76
+ ? curr
77
+ : prev;
78
+ });
79
+ setActiveId(closest.target.id);
80
+ }
81
+ };
82
+
83
+ observerRef.current = new IntersectionObserver(callback, {
84
+ rootMargin: "-100px 0px -70% 0px",
85
+ threshold: [0, 1],
86
+ });
87
+
88
+ const observeHeadings = () => {
89
+ headings.forEach(({ id }) => {
90
+ const el = document.getElementById(id);
91
+ if (el) {
92
+ observerRef.current!.observe(el);
93
+ }
94
+ });
95
+ };
96
+
97
+ // Initial observation
98
+ observeHeadings();
99
+
100
+ // Re-observe if content changes
101
+ const timeoutId = setTimeout(observeHeadings, 1000);
102
+
103
+ // Scroll listener to detect bottom of page
104
+ const handleScroll = () => {
105
+ const scrollPosition = window.innerHeight + window.pageYOffset;
106
+ const bodyHeight = document.documentElement.scrollHeight;
107
+
108
+ // If we're within 50px of the bottom, activate the last heading
109
+ if (scrollPosition >= bodyHeight - 50) {
110
+ setActiveId(headings[headings.length - 1].id);
111
+ }
112
+ };
113
+
114
+ window.addEventListener("scroll", handleScroll, { passive: true });
115
+
116
+ return () => {
117
+ observerRef.current?.disconnect();
118
+ clearTimeout(timeoutId);
119
+ window.removeEventListener("scroll", handleScroll);
120
+ };
121
+ }, [headings, location.pathname]);
122
+
123
+ // Autoscroll TOC list when activeId changes
124
+ useEffect(() => {
125
+ if (!activeId || !listRef.current) return;
126
+
127
+ const activeLink = listRef.current.querySelector(
128
+ `a[href="#${activeId}"]`,
129
+ ) as HTMLElement;
130
+
131
+ if (activeLink) {
132
+ const container = listRef.current.closest(
133
+ ".boltdocs-on-this-page",
134
+ ) as HTMLElement;
135
+ if (!container) return;
136
+
137
+ const linkRect = activeLink.getBoundingClientRect();
138
+ const containerRect = container.getBoundingClientRect();
139
+
140
+ const isVisible =
141
+ linkRect.top >= containerRect.top &&
142
+ linkRect.bottom <= containerRect.bottom;
143
+
144
+ if (!isVisible) {
145
+ activeLink.scrollIntoView({
146
+ behavior: "smooth",
147
+ block: "nearest",
148
+ });
149
+ }
150
+ }
151
+ }, [activeId]);
152
+
153
+ const handleClick = useCallback(
154
+ (e: React.MouseEvent<HTMLAnchorElement>, id: string) => {
155
+ e.preventDefault();
156
+ const el = document.getElementById(id);
157
+ if (el) {
158
+ const offset = 80;
159
+ const bodyRect = document.body.getBoundingClientRect().top;
160
+ const elementRect = el.getBoundingClientRect().top;
161
+ const elementPosition = elementRect - bodyRect;
162
+ const offsetPosition = elementPosition - offset;
163
+
164
+ window.scrollTo({
165
+ top: offsetPosition,
166
+ behavior: "smooth",
167
+ });
168
+
169
+ setActiveId(id);
170
+ window.history.pushState(null, "", `#${id}`);
171
+ }
172
+ },
173
+ [],
174
+ );
175
+
176
+ if (headings.length === 0) return null;
177
+
178
+ return (
179
+ <nav className="boltdocs-on-this-page" aria-label="Table of contents">
180
+ <p className="on-this-page-title">On this page</p>
181
+ <div className="on-this-page-container">
182
+ <div className="toc-indicator" style={indicatorStyle} />
183
+ <ul className="on-this-page-list" ref={listRef}>
184
+ {headings.map((h) => (
185
+ <li key={h.id} className={h.level === 3 ? "toc-indent" : ""}>
186
+ <a
187
+ href={`#${h.id}`}
188
+ className={`toc-link ${activeId === h.id ? "active" : ""}`}
189
+ aria-current={activeId === h.id ? "true" : undefined}
190
+ onClick={(e) => handleClick(e, h.id)}
191
+ >
192
+ {h.text}
193
+ </a>
194
+ </li>
195
+ ))}
196
+ </ul>
197
+ </div>
198
+
199
+ {/* Need help? section */}
200
+ {(editLink || communityHelp) && (
201
+ <div className="toc-help">
202
+ <p className="toc-help-title">Need help?</p>
203
+ <ul className="toc-help-links">
204
+ {editLink && filePath && (
205
+ <li>
206
+ <a
207
+ href={editLink.replace(":path", filePath)}
208
+ target="_blank"
209
+ rel="noopener noreferrer"
210
+ className="toc-help-link"
211
+ >
212
+ <Pencil size={16} />
213
+ Edit this page
214
+ </a>
215
+ </li>
216
+ )}
217
+ {communityHelp && (
218
+ <li>
219
+ <a
220
+ href={communityHelp}
221
+ target="_blank"
222
+ rel="noopener noreferrer"
223
+ className="toc-help-link"
224
+ >
225
+ <CircleHelp size={16} />
226
+ Community help
227
+ </a>
228
+ </li>
229
+ )}
230
+ </ul>
231
+ </div>
232
+ )}
233
+ </nav>
234
+ );
235
+ }
@@ -1 +1 @@
1
- export { OnThisPage } from "./OnThisPage";
1
+ export { OnThisPage } from "./OnThisPage";