boltdocs 2.7.9 → 2.7.11
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/dist/{cache-DorPMFgW.cjs → cache-Ba-DZQNH.cjs} +1 -1
- package/dist/{cache-CQKlT4fI.mjs → cache-BuMZ58L5.mjs} +1 -1
- package/dist/chunk-CU-zTemE.cjs +6 -0
- package/dist/client/index.cjs +1929 -1
- package/dist/client/index.js +1880 -1
- package/dist/client/mdx.cjs +7 -1
- package/dist/client/mdx.js +7 -1
- package/dist/client/primitives.cjs +60 -1
- package/dist/client/primitives.js +20 -1
- package/dist/docs-layout-BXHV0xw_.cjs +1431 -0
- package/dist/docs-layout-DwFndmj5.js +1231 -0
- package/dist/doctor-Be7Ly1oM.mjs +21 -0
- package/dist/{doctor-D4_Y7M4p.cjs → doctor-CrytFkqW.cjs} +1 -1
- package/dist/doctor-jMxWZyLJ.cjs +21 -0
- package/dist/generator-CHqxiQhF.cjs +21 -0
- package/dist/generator-ClVanhvi.mjs +21 -0
- package/dist/icons-dev-3cZMyt8r.cjs +1204 -0
- package/dist/icons-dev-Df8OQ481.js +839 -0
- package/dist/image-DtrI2cw3.cjs +268 -0
- package/dist/image-jxPb-2iV.js +214 -0
- package/dist/mdx-BdWkJTeB.cjs +523 -0
- package/dist/mdx-UTTLFWJq.js +494 -0
- package/dist/meta-loader-CWg2gnbY.mjs +6 -0
- package/dist/meta-loader-Cv9O0Pzl.cjs +6 -0
- package/dist/node/cli-entry.cjs +1 -1
- package/dist/node/cli-entry.mjs +1 -1
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.mjs +1 -1
- package/dist/node/routes/worker.cjs +1 -1
- package/dist/node/routes/worker.mjs +1 -1
- package/dist/node-BSM4qcDK.cjs +111 -0
- package/dist/node-BspZN3R2.mjs +111 -0
- package/dist/{package-VfQM94VL.cjs → package-DIIrjuWI.cjs} +1 -1
- package/dist/{package-B4MD00N3.mjs → package-K0zsjGIz.mjs} +1 -1
- package/dist/{parser-Bh11BsdA.cjs → parser-Aq8LoH-0.cjs} +1 -1
- package/dist/{parser-DYRzXWmA.cjs → parser-CdNbqN5y.cjs} +1 -1
- package/dist/parser-nE792MLO.mjs +6 -0
- package/dist/rolldown-runtime-fkIsjY3S.mjs +6 -0
- package/dist/{routes-Co1mRM58.cjs → routes-2k3tbUmC.cjs} +1 -1
- package/dist/routes-CpxZIsMM.mjs +6 -0
- package/dist/{routes-CHf76Ye4.cjs → routes-DP1vmWRj.cjs} +1 -1
- package/dist/search-dialog-BHuIiUC6.js +8 -0
- package/dist/search-dialog-BNF10tDl.js +375 -0
- package/dist/search-dialog-BwkDuI9R.cjs +220 -0
- package/dist/search-dialog-C7xuvyNk.cjs +386 -0
- package/dist/search-dialog-CIQg6k8c.cjs +8 -0
- package/dist/search-dialog-D-DDN7zJ.js +208 -0
- package/dist/utils-CG65J0Sc.mjs +7 -0
- package/dist/utils-CKunkU96.cjs +7 -0
- package/dist/{worker-pool-BwU8ckrg.cjs → worker-pool-Crbqgw5R.cjs} +1 -1
- package/package.json +5 -5
- package/dist/chunk-Ds5LZdWN.cjs +0 -6
- package/dist/docs-layout-KoWNZc8_.js +0 -6
- package/dist/docs-layout-x2yKt2cL.cjs +0 -6
- package/dist/doctor-BD1BSB03.mjs +0 -23
- package/dist/doctor-BHc9ua6r.cjs +0 -23
- package/dist/generator-DGW6pkCC.cjs +0 -22
- package/dist/generator-Dv3wEmhZ.mjs +0 -22
- package/dist/icons-dev-B_RZIyxu.js +0 -6
- package/dist/icons-dev-BlV3wWFT.cjs +0 -6
- package/dist/image-BHhTvQzr.cjs +0 -6
- package/dist/image-CqKzYD8f.js +0 -6
- package/dist/mdx-DudBEac0.js +0 -7
- package/dist/mdx-r4cDQxWu.cjs +0 -7
- package/dist/meta-loader-0gJ4PtBC.cjs +0 -6
- package/dist/meta-loader-9IpAHWDS.mjs +0 -6
- package/dist/node-DBaH7kat.mjs +0 -111
- package/dist/node-t5C3Q85p.cjs +0 -111
- package/dist/parser-9cVdK7w9.mjs +0 -6
- package/dist/routes-DwrMa5-z.mjs +0 -6
- package/dist/search-dialog-B584t9ZF.js +0 -6
- package/dist/search-dialog-BvBopRsZ.cjs +0 -6
- package/dist/search-dialog-ByvGScjt.js +0 -6
- package/dist/search-dialog-Cyko6TJm.cjs +0 -6
- package/dist/search-dialog-D6BNohIJ.js +0 -6
- package/dist/search-dialog-DuYTIefy.cjs +0 -6
- package/dist/utils-BxNAXhZZ.mjs +0 -7
- package/dist/utils-Clzu7jvb.cjs +0 -7
- package/src/client/app/config-context.tsx +0 -51
- package/src/client/app/doc-page.tsx +0 -38
- package/src/client/app/docs-layout.tsx +0 -28
- package/src/client/app/head.tsx +0 -122
- package/src/client/app/helmet-compat.tsx +0 -36
- package/src/client/app/mdx-component.tsx +0 -8
- package/src/client/app/mdx-components-context.tsx +0 -72
- package/src/client/app/routes-context.tsx +0 -34
- package/src/client/app/scroll-handler.tsx +0 -74
- package/src/client/app/theme-context.tsx +0 -103
- package/src/client/app/ui-context.tsx +0 -42
- package/src/client/components/docs-layout-default.tsx +0 -85
- package/src/client/components/icons-dev.tsx +0 -282
- package/src/client/components/mdx/callout.tsx +0 -97
- package/src/client/components/mdx/card.tsx +0 -99
- package/src/client/components/mdx/cards.tsx +0 -27
- package/src/client/components/mdx/code-block.tsx +0 -184
- package/src/client/components/mdx/field.tsx +0 -33
- package/src/client/components/mdx/image.tsx +0 -44
- package/src/client/components/mdx/index.ts +0 -19
- package/src/client/components/mdx/table.tsx +0 -54
- package/src/client/components/mdx/typographics.tsx +0 -120
- package/src/client/components/mdx/use-code-block.ts +0 -34
- package/src/client/components/primitives/breadcrumbs.tsx +0 -54
- package/src/client/components/primitives/button-group.tsx +0 -54
- package/src/client/components/primitives/button.tsx +0 -6
- package/src/client/components/primitives/code-block.tsx +0 -120
- package/src/client/components/primitives/docs-layout.tsx +0 -125
- package/src/client/components/primitives/error-boundary.tsx +0 -107
- package/src/client/components/primitives/heading.tsx +0 -128
- package/src/client/components/primitives/helpers/observer.ts +0 -141
- package/src/client/components/primitives/image.tsx +0 -26
- package/src/client/components/primitives/link.tsx +0 -102
- package/src/client/components/primitives/menu.tsx +0 -137
- package/src/client/components/primitives/navbar.tsx +0 -466
- package/src/client/components/primitives/on-this-page.tsx +0 -430
- package/src/client/components/primitives/page-nav.tsx +0 -51
- package/src/client/components/primitives/popover.tsx +0 -28
- package/src/client/components/primitives/search-dialog.tsx +0 -193
- package/src/client/components/primitives/sidebar.tsx +0 -423
- package/src/client/components/primitives/skeleton.tsx +0 -26
- package/src/client/components/primitives/tabs.tsx +0 -70
- package/src/client/components/primitives/tooltip.tsx +0 -81
- package/src/client/components/primitives/types.ts +0 -11
- package/src/client/components/ui-base/banner.tsx +0 -66
- package/src/client/components/ui-base/breadcrumbs.tsx +0 -44
- package/src/client/components/ui-base/copy-markdown.tsx +0 -107
- package/src/client/components/ui-base/error-boundary.tsx +0 -15
- package/src/client/components/ui-base/github-stars.tsx +0 -29
- package/src/client/components/ui-base/icons.tsx +0 -240
- package/src/client/components/ui-base/index.ts +0 -16
- package/src/client/components/ui-base/last-updated.tsx +0 -27
- package/src/client/components/ui-base/navbar.tsx +0 -266
- package/src/client/components/ui-base/not-found.tsx +0 -26
- package/src/client/components/ui-base/on-this-page.tsx +0 -57
- package/src/client/components/ui-base/page-nav.tsx +0 -50
- package/src/client/components/ui-base/search-dialog.tsx +0 -163
- package/src/client/components/ui-base/search-highlight.tsx +0 -10
- package/src/client/components/ui-base/sidebar.tsx +0 -92
- package/src/client/components/ui-base/tabs.tsx +0 -83
- package/src/client/components/ui-base/theme-toggle.tsx +0 -130
- package/src/client/components/ui-base/version-i18n.tsx +0 -80
- package/src/client/hooks/index.ts +0 -13
- package/src/client/hooks/use-analytics.ts +0 -272
- package/src/client/hooks/use-breadcrumbs.ts +0 -22
- package/src/client/hooks/use-i18n.ts +0 -182
- package/src/client/hooks/use-localized-to.ts +0 -113
- package/src/client/hooks/use-location.ts +0 -5
- package/src/client/hooks/use-navbar.ts +0 -130
- package/src/client/hooks/use-page-nav.ts +0 -46
- package/src/client/hooks/use-routes.ts +0 -108
- package/src/client/hooks/use-search-highlight.ts +0 -185
- package/src/client/hooks/use-search.ts +0 -118
- package/src/client/hooks/use-sidebar.ts +0 -205
- package/src/client/hooks/use-tabs.ts +0 -46
- package/src/client/hooks/use-version.ts +0 -111
- package/src/client/index.ts +0 -31
- package/src/client/mdx.ts +0 -2
- package/src/client/primitives.ts +0 -19
- package/src/client/ssg/boltdocs-shell.tsx +0 -148
- package/src/client/ssg/create-routes.tsx +0 -473
- package/src/client/ssg/index.ts +0 -4
- package/src/client/ssg/mdx-page.tsx +0 -38
- package/src/client/store/boltdocs-context.tsx +0 -137
- package/src/client/theme/neutral.css +0 -141
- package/src/client/theme/reset.css +0 -189
- package/src/client/types.ts +0 -116
- package/src/client/utils/cn.ts +0 -6
- package/src/client/utils/copy-clipboard.ts +0 -22
- package/src/client/utils/get-base-file-path.ts +0 -21
- package/src/client/utils/github.ts +0 -121
- package/src/client/utils/i18n.ts +0 -23
- package/src/client/utils/path.ts +0 -9
- package/src/client/utils/react-to-text.ts +0 -34
- package/src/client/virtual.d.ts +0 -24
- /package/dist/{worker-pool-Bd8Y9KDv.mjs → worker-pool-CGn7DrLb.mjs} +0 -0
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import { useEffect } from 'react'
|
|
2
|
-
import { useLocation } from './use-location'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Hook to highlight search terms based on the 'hl' query parameter.
|
|
6
|
-
*/
|
|
7
|
-
export function useSearchHighlight(
|
|
8
|
-
containerSelector: string = '.boltdocs-page',
|
|
9
|
-
) {
|
|
10
|
-
const { search } = useLocation()
|
|
11
|
-
const query = new URLSearchParams(search).get('hl')
|
|
12
|
-
|
|
13
|
-
useEffect(() => {
|
|
14
|
-
if (!query) {
|
|
15
|
-
clearHighlights(containerSelector)
|
|
16
|
-
return
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const container = document.querySelector(containerSelector)
|
|
20
|
-
if (!container) return
|
|
21
|
-
|
|
22
|
-
let rafId: number
|
|
23
|
-
|
|
24
|
-
// Observe changes to the content (e.g. navigation or lazy loading)
|
|
25
|
-
const observer = new MutationObserver((mutations) => {
|
|
26
|
-
const hasExternalChanges = mutations.some((m) => {
|
|
27
|
-
const addedNodes = Array.from(m.addedNodes)
|
|
28
|
-
const removedNodes = Array.from(m.removedNodes)
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
addedNodes.some(
|
|
32
|
-
(n) =>
|
|
33
|
-
!(
|
|
34
|
-
n instanceof HTMLElement &&
|
|
35
|
-
n.hasAttribute('data-search-highlight')
|
|
36
|
-
),
|
|
37
|
-
) ||
|
|
38
|
-
removedNodes.some(
|
|
39
|
-
(n) =>
|
|
40
|
-
!(
|
|
41
|
-
n instanceof HTMLElement &&
|
|
42
|
-
n.hasAttribute('data-search-highlight')
|
|
43
|
-
),
|
|
44
|
-
)
|
|
45
|
-
)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
if (hasExternalChanges) {
|
|
49
|
-
run()
|
|
50
|
-
}
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
// Function to run highlighting
|
|
54
|
-
function run() {
|
|
55
|
-
cancelAnimationFrame(rafId)
|
|
56
|
-
rafId = requestAnimationFrame(() => {
|
|
57
|
-
// Disconnect to avoid observing our own cleanup/highlight cycle
|
|
58
|
-
observer.disconnect()
|
|
59
|
-
clearHighlights(containerSelector)
|
|
60
|
-
|
|
61
|
-
// Split query into individual words (minimum 2 chars)
|
|
62
|
-
const terms = query!
|
|
63
|
-
.split(/\s+/)
|
|
64
|
-
.map((t) => t.trim())
|
|
65
|
-
.filter((t) => t.length >= 2)
|
|
66
|
-
|
|
67
|
-
if (terms.length > 0) {
|
|
68
|
-
highlightTerms(container!, terms)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Re-observe
|
|
72
|
-
observer.observe(container!, { childList: true, subtree: true })
|
|
73
|
-
})
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Initial run
|
|
77
|
-
run()
|
|
78
|
-
|
|
79
|
-
return () => {
|
|
80
|
-
cancelAnimationFrame(rafId)
|
|
81
|
-
observer.disconnect()
|
|
82
|
-
clearHighlights(containerSelector)
|
|
83
|
-
}
|
|
84
|
-
}, [query, search, containerSelector])
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function clearHighlights(selector: string) {
|
|
88
|
-
const marks = document.querySelectorAll(
|
|
89
|
-
`${selector} mark[data-search-highlight]`,
|
|
90
|
-
)
|
|
91
|
-
marks.forEach((mark) => {
|
|
92
|
-
try {
|
|
93
|
-
const parent = mark.parentNode
|
|
94
|
-
if (parent && parent.contains(mark)) {
|
|
95
|
-
const text = mark.textContent || ''
|
|
96
|
-
parent.replaceChild(document.createTextNode(text), mark)
|
|
97
|
-
}
|
|
98
|
-
} catch (e) {
|
|
99
|
-
// Ignore DOM errors during cleanup
|
|
100
|
-
}
|
|
101
|
-
})
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function highlightTerms(container: Element, terms: string[]) {
|
|
105
|
-
const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT, {
|
|
106
|
-
acceptNode: (node) => {
|
|
107
|
-
const parent = node.parentElement
|
|
108
|
-
if (
|
|
109
|
-
parent &&
|
|
110
|
-
(parent.tagName === 'SCRIPT' ||
|
|
111
|
-
parent.tagName === 'STYLE' ||
|
|
112
|
-
parent.tagName === 'MARK' ||
|
|
113
|
-
parent.closest('pre') ||
|
|
114
|
-
parent.closest('code'))
|
|
115
|
-
) {
|
|
116
|
-
return NodeFilter.FILTER_REJECT
|
|
117
|
-
}
|
|
118
|
-
return NodeFilter.FILTER_ACCEPT
|
|
119
|
-
},
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
const nodes: Text[] = []
|
|
123
|
-
let node: Node | null
|
|
124
|
-
while ((node = walker.nextNode())) {
|
|
125
|
-
nodes.push(node as Text)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Create a combined regex for all terms
|
|
129
|
-
// Accent-insensitive helper: replaces 'a' with '[aáàä...]'
|
|
130
|
-
const accentMap: Record<string, string> = {
|
|
131
|
-
a: '[aáàäâã]',
|
|
132
|
-
e: '[eéèëê]',
|
|
133
|
-
i: '[iíìïî]',
|
|
134
|
-
o: '[oóòöôõ]',
|
|
135
|
-
u: '[uúùüû]',
|
|
136
|
-
n: '[nñ]',
|
|
137
|
-
c: '[cç]',
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const prepareRegex = (term: string) => {
|
|
141
|
-
let pattern = term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
142
|
-
// Make it accent insensitive
|
|
143
|
-
pattern = pattern
|
|
144
|
-
.split('')
|
|
145
|
-
.map((char) => {
|
|
146
|
-
const lower = char.toLowerCase()
|
|
147
|
-
return accentMap[lower] || char
|
|
148
|
-
})
|
|
149
|
-
.join('')
|
|
150
|
-
return pattern
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const combinedPattern = terms.map(prepareRegex).join('|')
|
|
154
|
-
const regex = new RegExp(`(${combinedPattern})`, 'gi')
|
|
155
|
-
|
|
156
|
-
const matchRegexes = terms.map((term) => {
|
|
157
|
-
const p = prepareRegex(term)
|
|
158
|
-
return new RegExp(`^${p}$`, 'i')
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
nodes.forEach((textNode) => {
|
|
162
|
-
const text = textNode.textContent
|
|
163
|
-
if (text && regex.test(text)) {
|
|
164
|
-
const fragment = document.createDocumentFragment()
|
|
165
|
-
const parts = text.split(regex)
|
|
166
|
-
|
|
167
|
-
parts.forEach((part) => {
|
|
168
|
-
const isMatch = matchRegexes.some((rx) => rx.test(part))
|
|
169
|
-
|
|
170
|
-
if (isMatch) {
|
|
171
|
-
const mark = document.createElement('mark')
|
|
172
|
-
mark.textContent = part
|
|
173
|
-
mark.setAttribute('data-search-highlight', 'true')
|
|
174
|
-
fragment.appendChild(mark)
|
|
175
|
-
} else if (part) {
|
|
176
|
-
fragment.appendChild(document.createTextNode(part))
|
|
177
|
-
}
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
if (textNode.parentNode) {
|
|
181
|
-
textNode.parentNode.replaceChild(fragment, textNode)
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
})
|
|
185
|
-
}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { useState, useMemo, useEffect } from 'react'
|
|
2
|
-
import { Index } from 'flexsearch'
|
|
3
|
-
import { useRoutes } from './use-routes'
|
|
4
|
-
import type { ComponentRoute } from '../types'
|
|
5
|
-
// @ts-expect-error
|
|
6
|
-
import searchData from 'virtual:boltdocs-search'
|
|
7
|
-
|
|
8
|
-
interface SearchDataItem {
|
|
9
|
-
id: string
|
|
10
|
-
title: string
|
|
11
|
-
content: string
|
|
12
|
-
url: string
|
|
13
|
-
display: string
|
|
14
|
-
locale?: string
|
|
15
|
-
version?: string
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function useSearch(routes: ComponentRoute[]) {
|
|
19
|
-
const { currentLocale, currentVersion } = useRoutes()
|
|
20
|
-
const [isOpen, setIsOpen] = useState(false)
|
|
21
|
-
const [query, setQuery] = useState('')
|
|
22
|
-
const [index, setIndex] = useState<Index | null>(null)
|
|
23
|
-
|
|
24
|
-
// Initialize FlexSearch index once
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
if (!isOpen || index) return
|
|
27
|
-
|
|
28
|
-
const newIndex = new Index({
|
|
29
|
-
preset: 'match',
|
|
30
|
-
tokenize: 'full',
|
|
31
|
-
resolution: 9,
|
|
32
|
-
cache: true,
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
// Index all documents
|
|
36
|
-
for (const doc of searchData as SearchDataItem[]) {
|
|
37
|
-
newIndex.add(doc.id, `${doc.title} ${doc.content}`)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
setIndex(newIndex)
|
|
41
|
-
}, [isOpen, index])
|
|
42
|
-
|
|
43
|
-
// Pre-index searchData for O(1) lookups
|
|
44
|
-
const searchDataMap = useMemo(() => {
|
|
45
|
-
const map = new Map<string, SearchDataItem>()
|
|
46
|
-
for (const doc of searchData as SearchDataItem[]) {
|
|
47
|
-
map.set(doc.id, doc)
|
|
48
|
-
}
|
|
49
|
-
return map
|
|
50
|
-
}, [])
|
|
51
|
-
|
|
52
|
-
const list = useMemo(() => {
|
|
53
|
-
if (!query) {
|
|
54
|
-
// Default results: just active routes
|
|
55
|
-
return routes
|
|
56
|
-
.filter((r) => {
|
|
57
|
-
const localeMatch = !currentLocale || r.locale === currentLocale
|
|
58
|
-
const versionMatch = !currentVersion || r.version === currentVersion
|
|
59
|
-
return localeMatch && versionMatch
|
|
60
|
-
})
|
|
61
|
-
.slice(0, 10)
|
|
62
|
-
.map((r) => ({
|
|
63
|
-
id: r.path,
|
|
64
|
-
title: r.title,
|
|
65
|
-
path: r.path,
|
|
66
|
-
bio: r.description || '',
|
|
67
|
-
groupTitle: r.groupTitle,
|
|
68
|
-
}))
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (!index) return []
|
|
72
|
-
|
|
73
|
-
const searchResults = index.search(query, {
|
|
74
|
-
limit: 20,
|
|
75
|
-
suggest: true,
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
const results: any[] = []
|
|
79
|
-
const seen = new Set<string>()
|
|
80
|
-
|
|
81
|
-
for (const id of searchResults) {
|
|
82
|
-
const doc = searchDataMap.get(id as string)
|
|
83
|
-
if (!doc) continue
|
|
84
|
-
|
|
85
|
-
// Filter by locale and version
|
|
86
|
-
const localeMatch = !currentLocale || doc.locale === currentLocale
|
|
87
|
-
const versionMatch = !currentVersion || doc.version === currentVersion
|
|
88
|
-
if (!localeMatch || !versionMatch) continue
|
|
89
|
-
|
|
90
|
-
if (seen.has(doc.url)) continue
|
|
91
|
-
seen.add(doc.url)
|
|
92
|
-
|
|
93
|
-
results.push({
|
|
94
|
-
id: doc.url,
|
|
95
|
-
title: doc.title,
|
|
96
|
-
path: doc.url,
|
|
97
|
-
bio: doc.display,
|
|
98
|
-
groupTitle: doc.display.split(' > ')[0],
|
|
99
|
-
isHeading: doc.url.includes('#'),
|
|
100
|
-
})
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return results.slice(0, 10)
|
|
104
|
-
}, [query, index, currentLocale, currentVersion, routes, searchDataMap])
|
|
105
|
-
|
|
106
|
-
return {
|
|
107
|
-
isOpen,
|
|
108
|
-
setIsOpen,
|
|
109
|
-
query,
|
|
110
|
-
setQuery,
|
|
111
|
-
list,
|
|
112
|
-
input: {
|
|
113
|
-
value: query,
|
|
114
|
-
onChange: (e: React.ChangeEvent<HTMLInputElement>) =>
|
|
115
|
-
setQuery(e.target.value),
|
|
116
|
-
},
|
|
117
|
-
}
|
|
118
|
-
}
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
import { useMemo } from 'react'
|
|
2
|
-
import { useLocation } from 'react-router-dom'
|
|
3
|
-
import { useConfig } from '../app/config-context'
|
|
4
|
-
import type { ComponentRoute } from '../types'
|
|
5
|
-
import { normalizePath } from '../utils/path'
|
|
6
|
-
|
|
7
|
-
export function useSidebar(routes: ComponentRoute[]) {
|
|
8
|
-
const config = useConfig()
|
|
9
|
-
const location = useLocation()
|
|
10
|
-
|
|
11
|
-
const currentPath = normalizePath(location.pathname)
|
|
12
|
-
|
|
13
|
-
return useMemo(() => {
|
|
14
|
-
const activeRoute = routes.find(
|
|
15
|
-
(r) => normalizePath(r.path) === currentPath,
|
|
16
|
-
)
|
|
17
|
-
const activeTabId = activeRoute?.tab?.toLowerCase()
|
|
18
|
-
|
|
19
|
-
const filteredRoutes = activeTabId
|
|
20
|
-
? routes.filter((r) => !r.tab || r.tab.toLowerCase() === activeTabId)
|
|
21
|
-
: routes
|
|
22
|
-
|
|
23
|
-
const directoryMeta: Record<string, any> = {}
|
|
24
|
-
if (config.directoryMeta) {
|
|
25
|
-
for (const [key, value] of Object.entries(config.directoryMeta)) {
|
|
26
|
-
const cleanKey = key
|
|
27
|
-
.split('/')
|
|
28
|
-
.filter((part) => !part.startsWith('(') || !part.endsWith(')'))
|
|
29
|
-
.map((part) => part.replace(/^\d+-/, ''))
|
|
30
|
-
.join('/')
|
|
31
|
-
directoryMeta[cleanKey === '' ? '.' : cleanKey] = value
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// 1. Helper to format labels
|
|
36
|
-
const capitalize = (str: string) =>
|
|
37
|
-
str.charAt(0).toUpperCase() + str.slice(1).replace(/-/g, ' ')
|
|
38
|
-
|
|
39
|
-
// 2. Define recursive tree builder
|
|
40
|
-
const rootNodesMap = new Map<string, ComponentRoute>()
|
|
41
|
-
const ungrouped: ComponentRoute[] = []
|
|
42
|
-
|
|
43
|
-
// Helper to find or create nested folders recursively
|
|
44
|
-
const getOrCreateNode = (
|
|
45
|
-
parts: string[],
|
|
46
|
-
rootStore: Map<string, ComponentRoute>,
|
|
47
|
-
) => {
|
|
48
|
-
let currentMap = rootStore
|
|
49
|
-
let parentPath = ''
|
|
50
|
-
let lastNode: ComponentRoute | null = null
|
|
51
|
-
|
|
52
|
-
for (let i = 0; i < parts.length; i++) {
|
|
53
|
-
const segment = parts[i]
|
|
54
|
-
const currentRelPath = parentPath ? `${parentPath}/${segment}` : segment
|
|
55
|
-
|
|
56
|
-
if (!currentMap.has(segment)) {
|
|
57
|
-
const meta = directoryMeta[currentRelPath] || {}
|
|
58
|
-
const newNode: ComponentRoute = {
|
|
59
|
-
path: '#', // Placeholder
|
|
60
|
-
title: meta.title || capitalize(segment),
|
|
61
|
-
componentPath: '',
|
|
62
|
-
filePath: '',
|
|
63
|
-
icon: meta.icon,
|
|
64
|
-
groupPosition: typeof meta.order === 'number' ? meta.order : 999,
|
|
65
|
-
subRoutes: [],
|
|
66
|
-
}
|
|
67
|
-
currentMap.set(segment, newNode)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
lastNode = currentMap.get(segment)!
|
|
71
|
-
|
|
72
|
-
// Create inner subRoutes mapping helper
|
|
73
|
-
if (!(lastNode as any)._subMap) {
|
|
74
|
-
;(lastNode as any)._subMap = new Map<string, ComponentRoute>()
|
|
75
|
-
}
|
|
76
|
-
currentMap = (lastNode as any)._subMap as Map<string, ComponentRoute>
|
|
77
|
-
parentPath = currentRelPath
|
|
78
|
-
}
|
|
79
|
-
return lastNode
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// 3. Sort input routes initially by their internal position/ordering
|
|
83
|
-
const sortedRoutes = [...filteredRoutes].sort((a, b) => {
|
|
84
|
-
const posA = a.sidebarPosition ?? a.order ?? 999
|
|
85
|
-
const posB = b.sidebarPosition ?? b.order ?? 999
|
|
86
|
-
return posA - posB
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
// 4. Distribute routes into tree
|
|
90
|
-
for (const route of sortedRoutes) {
|
|
91
|
-
if (route.sidebarHidden) continue
|
|
92
|
-
|
|
93
|
-
const parts = route.slugParts || []
|
|
94
|
-
const fileName = route.filePath.split('/').pop() || ''
|
|
95
|
-
const isIndex = /^index\.mdx?$/.test(fileName)
|
|
96
|
-
|
|
97
|
-
if (parts.length === 0) {
|
|
98
|
-
// Top level route (not in subfolder)
|
|
99
|
-
if (route.filePath) ungrouped.push(route)
|
|
100
|
-
continue
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (isIndex) {
|
|
104
|
-
// Index files populate the CONTAINER object itself
|
|
105
|
-
const containerNode = getOrCreateNode(parts, rootNodesMap)
|
|
106
|
-
if (containerNode) {
|
|
107
|
-
// Merge properties onto the container so it becomes clickable
|
|
108
|
-
containerNode.path = route.path
|
|
109
|
-
containerNode.title = route.title || containerNode.title
|
|
110
|
-
containerNode.icon = route.icon || containerNode.icon
|
|
111
|
-
containerNode.badge = route.badge
|
|
112
|
-
containerNode.sidebarPosition = route.sidebarPosition
|
|
113
|
-
containerNode.frontmatter = route.frontmatter
|
|
114
|
-
}
|
|
115
|
-
} else {
|
|
116
|
-
// Normal leaf file nested under path
|
|
117
|
-
const parentNode = getOrCreateNode(parts, rootNodesMap)
|
|
118
|
-
if (parentNode) {
|
|
119
|
-
parentNode.subRoutes!.push(route)
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// 5. Recursive sorting and cleanup helper
|
|
125
|
-
const finalizeTree = (
|
|
126
|
-
nodes: ComponentRoute[],
|
|
127
|
-
currentPathPrefix: string = '',
|
|
128
|
-
): ComponentRoute[] => {
|
|
129
|
-
nodes.forEach((node) => {
|
|
130
|
-
// 1. Pull child nodes from internal Map store into subRoutes
|
|
131
|
-
if ((node as any)._subMap) {
|
|
132
|
-
const childDirs = Array.from(
|
|
133
|
-
((node as any)._subMap as Map<string, ComponentRoute>).values(),
|
|
134
|
-
)
|
|
135
|
-
node.subRoutes = [...(node.subRoutes || []), ...childDirs]
|
|
136
|
-
delete (node as any)._subMap
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// 2. Recursively process grandchildren
|
|
140
|
-
if (node.subRoutes && node.subRoutes.length > 0) {
|
|
141
|
-
node.subRoutes = finalizeTree(node.subRoutes)
|
|
142
|
-
}
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
// 3. Sort this specific depth layer
|
|
146
|
-
return nodes.sort((a, b) => {
|
|
147
|
-
// Position ordering
|
|
148
|
-
const posA = a.sidebarPosition ?? a.groupPosition ?? 999
|
|
149
|
-
const posB = b.sidebarPosition ?? b.groupPosition ?? 999
|
|
150
|
-
|
|
151
|
-
if (posA !== posB) return posA - posB
|
|
152
|
-
|
|
153
|
-
// Fallback alphabetical
|
|
154
|
-
return a.title.localeCompare(b.title)
|
|
155
|
-
})
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Finalize top-level groups
|
|
159
|
-
const rawGroups = Array.from(rootNodesMap.values())
|
|
160
|
-
const finalizedTopNodes = finalizeTree(rawGroups)
|
|
161
|
-
|
|
162
|
-
// Map finalized top nodes to expected format [{ title, routes }]
|
|
163
|
-
const groups = finalizedTopNodes.map((node) => {
|
|
164
|
-
// To match current primitives expectations, a 'group' is the top-level container.
|
|
165
|
-
// If the top node is already structured as a ComponentRoute, we wrap it.
|
|
166
|
-
return {
|
|
167
|
-
slug: node.title.toLowerCase().replace(/\s+/g, '-'),
|
|
168
|
-
title: node.title,
|
|
169
|
-
icon: node.icon,
|
|
170
|
-
routes: [node], // The primitives sidebar renderer iterates topGroup.routes and recurses inside.
|
|
171
|
-
}
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
// Wait, actually the legacy Sidebar.tsx treats "groups" as visual wrappers with headers,
|
|
175
|
-
// and "routes" inside as the start of items. If we want top-level direct items, they map to 'ungrouped'.
|
|
176
|
-
// Let's return grouped items natively.
|
|
177
|
-
|
|
178
|
-
// RE-DESIGN LEGACY COMPATIBILITY:
|
|
179
|
-
// If user wants strict backwards layout, we unwrap the very top layer!
|
|
180
|
-
const legacyCompatibleGroups = finalizedTopNodes
|
|
181
|
-
.map((node) => {
|
|
182
|
-
// Check if it's a container with subitems. If it is, make IT the group header!
|
|
183
|
-
if (node.subRoutes && node.subRoutes.length > 0) {
|
|
184
|
-
return {
|
|
185
|
-
slug: node.title.toLowerCase().replace(/\s+/g, '-'),
|
|
186
|
-
title: node.title,
|
|
187
|
-
icon: node.icon,
|
|
188
|
-
routes: node.subRoutes, // Unwrap children as top-level list underneath the visual group title!
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
// If it's standalone, send it to ungrouped
|
|
192
|
-
ungrouped.push(node)
|
|
193
|
-
return null
|
|
194
|
-
})
|
|
195
|
-
.filter(Boolean) as any[]
|
|
196
|
-
|
|
197
|
-
return {
|
|
198
|
-
groups: legacyCompatibleGroups,
|
|
199
|
-
ungrouped: finalizeTree(ungrouped),
|
|
200
|
-
activeRoute,
|
|
201
|
-
activePath: currentPath,
|
|
202
|
-
config,
|
|
203
|
-
}
|
|
204
|
-
}, [routes, config, currentPath])
|
|
205
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { useLocation } from 'react-router-dom'
|
|
2
|
-
import { useEffect, useState, useRef } from 'react'
|
|
3
|
-
import type { ComponentRoute, BoltdocsTab } from '../types'
|
|
4
|
-
import { normalizePath } from '../utils/path'
|
|
5
|
-
|
|
6
|
-
export function useTabs(
|
|
7
|
-
tabs: BoltdocsTab[] = [],
|
|
8
|
-
routes: ComponentRoute[] = [],
|
|
9
|
-
) {
|
|
10
|
-
const location = useLocation()
|
|
11
|
-
const tabRefs = useRef<(HTMLAnchorElement | null)[]>([])
|
|
12
|
-
const [indicatorStyle, setIndicatorStyle] = useState<React.CSSProperties>({
|
|
13
|
-
opacity: 0,
|
|
14
|
-
transform: 'translateX(0) scaleX(0)',
|
|
15
|
-
width: 0,
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
const currentPath = normalizePath(location.pathname)
|
|
19
|
-
|
|
20
|
-
const activeRoute = routes.find((r) => normalizePath(r.path) === currentPath)
|
|
21
|
-
const activeTabId = activeRoute?.tab?.toLowerCase()
|
|
22
|
-
const activeIndex = tabs.findIndex(
|
|
23
|
-
(tab) => tab.id.toLowerCase() === activeTabId,
|
|
24
|
-
)
|
|
25
|
-
const finalActiveIndex = activeIndex === -1 ? 0 : activeIndex
|
|
26
|
-
|
|
27
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: Updated pointer to the tab
|
|
28
|
-
useEffect(() => {
|
|
29
|
-
const activeTab = tabRefs.current[finalActiveIndex]
|
|
30
|
-
if (activeTab) {
|
|
31
|
-
setIndicatorStyle({
|
|
32
|
-
opacity: 1,
|
|
33
|
-
width: activeTab.offsetWidth,
|
|
34
|
-
transform: `translateX(${activeTab.offsetLeft}px)`,
|
|
35
|
-
})
|
|
36
|
-
}
|
|
37
|
-
}, [finalActiveIndex, tabs.length, location.pathname])
|
|
38
|
-
|
|
39
|
-
return {
|
|
40
|
-
tabs,
|
|
41
|
-
activeIndex: finalActiveIndex,
|
|
42
|
-
indicatorStyle,
|
|
43
|
-
tabRefs,
|
|
44
|
-
activeTabId,
|
|
45
|
-
}
|
|
46
|
-
}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { useMemo } from 'react'
|
|
2
|
-
import { useNavigate } from 'react-router-dom'
|
|
3
|
-
import { getBaseFilePath } from '../utils/get-base-file-path'
|
|
4
|
-
import { useRoutes } from './use-routes'
|
|
5
|
-
import { useConfig } from '../app/config-context'
|
|
6
|
-
import { useBoltdocsContext } from '../store/boltdocs-context'
|
|
7
|
-
import type { BoltdocsVersion } from '../../shared/types'
|
|
8
|
-
|
|
9
|
-
export interface VersionOption {
|
|
10
|
-
key: BoltdocsVersion
|
|
11
|
-
label: string
|
|
12
|
-
value: string
|
|
13
|
-
isCurrent: boolean
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface UseVersionReturn {
|
|
17
|
-
currentVersion: BoltdocsVersion | undefined
|
|
18
|
-
currentVersionLabel: string | undefined
|
|
19
|
-
availableVersions: VersionOption[]
|
|
20
|
-
handleVersionChange: (version: BoltdocsVersion) => void
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Hook to manage and switch between different versions of the documentation.
|
|
25
|
-
*/
|
|
26
|
-
export function useVersion(): UseVersionReturn {
|
|
27
|
-
const navigate = useNavigate()
|
|
28
|
-
const config = useConfig()
|
|
29
|
-
const { allRoutes, currentRoute, currentVersion, currentLocale } = useRoutes()
|
|
30
|
-
const versions = config.versions
|
|
31
|
-
const { setVersion } = useBoltdocsContext()
|
|
32
|
-
|
|
33
|
-
const handleVersionChange = (version: string) => {
|
|
34
|
-
if (!versions || version === currentVersion) return
|
|
35
|
-
|
|
36
|
-
// Update store
|
|
37
|
-
setVersion(version)
|
|
38
|
-
|
|
39
|
-
// 3. Attempt derivation or deployment of navigation target
|
|
40
|
-
const base = config.base || '/docs'
|
|
41
|
-
const safeBase = base.replace(/\/$/, '')
|
|
42
|
-
let targetPath = `${safeBase}/${version}${currentLocale ? `/${currentLocale}` : ''}`
|
|
43
|
-
|
|
44
|
-
if (currentRoute) {
|
|
45
|
-
const baseFile = getBaseFilePath(
|
|
46
|
-
currentRoute.filePath,
|
|
47
|
-
currentRoute.version,
|
|
48
|
-
currentRoute.locale,
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
const targetRoute = allRoutes.find(
|
|
52
|
-
(r) =>
|
|
53
|
-
getBaseFilePath(r.filePath, r.version, r.locale) === baseFile &&
|
|
54
|
-
(r.version || versions.defaultVersion) === version &&
|
|
55
|
-
(!config.i18n ||
|
|
56
|
-
(r.locale || config.i18n.defaultLocale) === currentLocale),
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
if (targetRoute) {
|
|
60
|
-
targetPath = targetRoute.path
|
|
61
|
-
} else {
|
|
62
|
-
const versionIndexRoute = allRoutes.find(
|
|
63
|
-
(r) =>
|
|
64
|
-
getBaseFilePath(r.filePath, r.version, r.locale) === 'index.md' &&
|
|
65
|
-
(r.version || versions.defaultVersion) === version &&
|
|
66
|
-
(!config.i18n ||
|
|
67
|
-
(r.locale || config.i18n.defaultLocale) === currentLocale),
|
|
68
|
-
)
|
|
69
|
-
if (versionIndexRoute) {
|
|
70
|
-
targetPath = versionIndexRoute.path
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
} else {
|
|
74
|
-
// Recovery mode: if currently on a 404, attempt to find ANY document in the target version
|
|
75
|
-
const fallbackRoute = allRoutes.find(
|
|
76
|
-
(r) =>
|
|
77
|
-
(r.version || versions.defaultVersion) === version &&
|
|
78
|
-
(!config.i18n ||
|
|
79
|
-
(r.locale || config.i18n.defaultLocale) === currentLocale),
|
|
80
|
-
)
|
|
81
|
-
if (fallbackRoute) {
|
|
82
|
-
targetPath = fallbackRoute.path
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
navigate(targetPath)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const currentVersionConfig = versions?.versions?.find?.(
|
|
90
|
-
(v) => v.path === currentVersion,
|
|
91
|
-
)
|
|
92
|
-
const currentVersionLabel = currentVersionConfig?.label || currentVersion
|
|
93
|
-
|
|
94
|
-
const availableVersions = useMemo(() => {
|
|
95
|
-
return versions
|
|
96
|
-
? versions.versions.map((v) => ({
|
|
97
|
-
key: v.path as BoltdocsVersion,
|
|
98
|
-
label: v.label,
|
|
99
|
-
value: v.path,
|
|
100
|
-
isCurrent: v.path === currentVersion,
|
|
101
|
-
}))
|
|
102
|
-
: []
|
|
103
|
-
}, [versions, currentVersion])
|
|
104
|
-
|
|
105
|
-
return {
|
|
106
|
-
currentVersion,
|
|
107
|
-
currentVersionLabel,
|
|
108
|
-
availableVersions,
|
|
109
|
-
handleVersionChange,
|
|
110
|
-
}
|
|
111
|
-
}
|
package/src/client/index.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
export type * from './types'
|
|
2
|
-
export type {
|
|
3
|
-
BoltdocsLocale,
|
|
4
|
-
BoltdocsVersion,
|
|
5
|
-
BoltdocsTypes,
|
|
6
|
-
} from '../shared/types'
|
|
7
|
-
export * from './ssg'
|
|
8
|
-
export { useConfig } from './app/config-context'
|
|
9
|
-
export { useTheme } from './app/theme-context'
|
|
10
|
-
export { useMdxComponents } from './app/mdx-components-context'
|
|
11
|
-
export { useUI } from './app/ui-context'
|
|
12
|
-
export * from './hooks/index'
|
|
13
|
-
export { DocsLayout } from './components/docs-layout-default'
|
|
14
|
-
export { Navbar } from './components/ui-base/navbar'
|
|
15
|
-
export { Sidebar } from './components/ui-base/sidebar'
|
|
16
|
-
export { OnThisPage } from './components/ui-base/on-this-page'
|
|
17
|
-
export { Breadcrumbs } from './components/ui-base/breadcrumbs'
|
|
18
|
-
export { PageNav } from './components/ui-base/page-nav'
|
|
19
|
-
export { ErrorBoundary } from './components/ui-base/error-boundary'
|
|
20
|
-
export { CopyMarkdown } from './components/ui-base/copy-markdown'
|
|
21
|
-
export { SearchDialog } from './components/ui-base/search-dialog'
|
|
22
|
-
export { NotFound } from './components/ui-base/not-found'
|
|
23
|
-
export { Card } from './components/mdx/card'
|
|
24
|
-
export { Cards } from './components/mdx/cards'
|
|
25
|
-
|
|
26
|
-
// Utilities
|
|
27
|
-
export { cn } from './utils/cn'
|
|
28
|
-
export { getTranslated } from './utils/i18n'
|
|
29
|
-
export { reactToText } from './utils/react-to-text'
|
|
30
|
-
export { copyToClipboard } from './utils/copy-clipboard'
|
|
31
|
-
export { getStarsRepo } from './utils/github'
|
package/src/client/mdx.ts
DELETED