boltdocs 2.3.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/base-ui/index.d.mts +3 -3
- package/dist/base-ui/index.d.ts +3 -3
- package/dist/base-ui/index.js +1 -1
- package/dist/base-ui/index.mjs +1 -1
- package/dist/chunk-2DI3OGHV.mjs +1 -0
- package/dist/chunk-64AJ5QLT.mjs +1 -0
- package/dist/chunk-DDX52BX4.mjs +1 -0
- package/dist/chunk-HRZDSFR5.mjs +1 -0
- package/dist/chunk-PPVDMDEL.mjs +1 -0
- package/dist/{chunk-HA6543SL.mjs → chunk-UBE4CKOA.mjs} +1 -1
- package/dist/chunk-UWT4AJTH.mjs +73 -0
- package/dist/chunk-WWJ7WKDI.mjs +1 -0
- package/dist/client/index.d.mts +15 -21
- package/dist/client/index.d.ts +15 -21
- package/dist/client/index.js +1 -1
- package/dist/client/index.mjs +1 -1
- package/dist/client/ssr.js +1 -1
- package/dist/client/ssr.mjs +1 -1
- package/dist/client/types.d.mts +1 -1
- package/dist/client/types.d.ts +1 -1
- package/dist/client/types.js +1 -1
- package/dist/{copy-markdown-CbS8X-qe.d.mts → copy-markdown--9yjpbyy.d.mts} +1 -1
- package/dist/{copy-markdown-C-90ixSe.d.ts → copy-markdown-l2MYkcG7.d.ts} +1 -1
- package/dist/hooks/index.d.mts +3 -3
- package/dist/hooks/index.d.ts +3 -3
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/index.d.ts +1 -1
- package/dist/{loading-B7X5Wchs.d.ts → loading-BwUos0wZ.d.mts} +2 -11
- package/dist/{loading-WuaQbsKb.d.mts → loading-nlnUD01v.d.ts} +2 -11
- package/dist/mdx/index.d.mts +4 -2
- package/dist/mdx/index.d.ts +4 -2
- package/dist/mdx/index.js +1 -1
- package/dist/mdx/index.mjs +1 -1
- package/dist/node/cli-entry.js +16 -17
- package/dist/node/cli-entry.mjs +1 -1
- package/dist/node/index.d.mts +0 -9
- package/dist/node/index.d.ts +0 -9
- package/dist/node/index.js +13 -14
- package/dist/node/index.mjs +1 -1
- package/dist/primitives/index.d.mts +11 -20
- package/dist/primitives/index.d.ts +11 -20
- package/dist/primitives/index.js +1 -1
- package/dist/primitives/index.mjs +1 -1
- package/dist/search-dialog-OONKKC5H.mjs +1 -0
- package/dist/{types-j7jvWsJj.d.ts → types-opDA2E9-.d.mts} +4 -11
- package/dist/{types-j7jvWsJj.d.mts → types-opDA2E9-.d.ts} +4 -11
- package/dist/{use-routes-Cd806kGw.d.ts → use-routes-DNwgTRpU.d.ts} +1 -1
- package/dist/{use-routes-DDL0_jkQ.d.mts → use-routes-DrT80Eom.d.mts} +1 -1
- package/package.json +1 -1
- package/src/client/app/index.tsx +20 -9
- package/src/client/app/mdx-components-context.tsx +2 -2
- package/src/client/app/mdx-page.tsx +0 -1
- package/src/client/app/scroll-handler.tsx +21 -10
- package/src/client/components/default-layout.tsx +0 -2
- package/src/client/components/docs-layout.tsx +34 -4
- package/src/client/components/icons-dev.tsx +154 -0
- package/src/client/components/mdx/code-block.tsx +57 -5
- package/src/client/components/mdx/component-preview.tsx +1 -0
- package/src/client/components/mdx/file-tree.tsx +35 -0
- package/src/client/components/primitives/helpers/observer.ts +30 -39
- package/src/client/components/primitives/index.ts +1 -0
- package/src/client/components/primitives/menu.tsx +18 -12
- package/src/client/components/primitives/navbar.tsx +31 -90
- package/src/client/components/primitives/on-this-page.tsx +7 -161
- package/src/client/components/primitives/popover.tsx +1 -2
- package/src/client/components/ui-base/copy-markdown.tsx +4 -10
- package/src/client/components/ui-base/index.ts +0 -1
- package/src/client/components/ui-base/navbar.tsx +10 -9
- package/src/client/hooks/use-navbar.ts +37 -6
- package/src/client/index.ts +0 -1
- package/src/client/theme/neutral.css +2 -3
- package/src/client/types.ts +2 -2
- package/src/node/config.ts +0 -14
- package/src/node/mdx/cache.ts +1 -1
- package/src/node/mdx/index.ts +2 -0
- package/src/node/mdx/rehype-shiki.ts +9 -0
- package/src/node/mdx/remark-code-meta.ts +35 -0
- package/src/node/mdx/remark-shiki.ts +1 -1
- package/src/node/plugin/entry.ts +21 -14
- package/src/node/plugin/index.ts +22 -4
- package/src/node/routes/parser.ts +3 -0
- package/src/node/ssg/index.ts +76 -16
- package/dist/chunk-22NXDNP4.mjs +0 -74
- package/dist/chunk-2HUVMMJU.mjs +0 -1
- package/dist/chunk-CRZGOE32.mjs +0 -1
- package/dist/chunk-RPUERTVC.mjs +0 -1
- package/dist/chunk-URTD6E6S.mjs +0 -1
- package/dist/chunk-W2NB4T6V.mjs +0 -1
- package/dist/search-dialog-ZRXBAQJ5.mjs +0 -1
- package/src/client/components/ui-base/progress-bar.tsx +0 -67
|
@@ -72,3 +72,157 @@ export const Bluesky = (props: WrapperProps) => (
|
|
|
72
72
|
<path d="M5.202 2.857C7.954 4.922 10.913 9.11 12 11.358c1.087-2.247 4.046-6.436 6.798-8.501C20.783 1.366 24 .213 24 3.883c0 .732-.42 6.156-.667 7.037-.856 3.061-3.978 3.842-6.755 3.37 4.854.826 6.089 3.562 3.422 6.299-5.065 5.196-7.28-1.304-7.847-2.97-.104-.305-.152-.448-.153-.327 0-.121-.05.022-.153.327-.568 1.666-2.782 8.166-7.847 2.97-2.667-2.737-1.432-5.473 3.422-6.3-2.777.473-5.899-.308-6.755-3.369C.42 10.04 0 4.615 0 3.883c0-3.67 3.217-2.517 5.202-1.026" />
|
|
73
73
|
</svg>
|
|
74
74
|
)
|
|
75
|
+
|
|
76
|
+
// Icons file
|
|
77
|
+
|
|
78
|
+
export const TypeScript = (props: WrapperProps) => (
|
|
79
|
+
<svg
|
|
80
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
81
|
+
fill="none"
|
|
82
|
+
viewBox="0 0 24 24"
|
|
83
|
+
{...wrapperProps(props)}
|
|
84
|
+
>
|
|
85
|
+
<title>{'TypeScript'}</title>
|
|
86
|
+
<path
|
|
87
|
+
fill="#2563EB"
|
|
88
|
+
d="M3.234 9.093V7.318h8.363v1.775H8.479V17.5H6.352V9.093H3.234zm15.263 1.153c-.04-.4-.21-.712-.512-.934-.301-.222-.71-.333-1.228-.333-.351 0-.648.05-.89.149-.242.096-.427.23-.557.403a.969.969 0 0 0-.189.586.838.838 0 0 0 .115.477c.086.136.204.254.353.353.149.097.321.181.517.254.195.07.404.13.626.179l.915.219c.444.1.852.232 1.223.397.371.166.693.37.965.612.271.242.482.527.631.855.152.328.23.704.234 1.129-.004.623-.163 1.163-.478 1.62-.311.454-.762.807-1.352 1.06-.587.248-1.294.372-2.123.372-.822 0-1.538-.126-2.147-.378-.607-.252-1.081-.624-1.422-1.118-.338-.497-.516-1.112-.532-1.845h2.083c.023.342.12.627.293.855.176.226.41.397.701.513a2.8 2.8 0 0 0 1 .168c.364 0 .68-.053.949-.159a1.45 1.45 0 0 0 .631-.442c.15-.189.224-.406.224-.651a.846.846 0 0 0-.204-.577c-.132-.156-.328-.288-.586-.398a5.964 5.964 0 0 0-.94-.298l-1.109-.278c-.858-.21-1.536-.536-2.033-.98-.497-.444-.744-1.042-.74-1.795-.004-.616.16-1.155.491-1.615.335-.461.794-.82 1.377-1.08.584-.258 1.247-.387 1.99-.387.755 0 1.414.13 1.978.388.567.258 1.007.618 1.322 1.079.315.46.477.994.488 1.6h-2.064z"
|
|
89
|
+
/>
|
|
90
|
+
</svg>
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
export const JavaScript = (props: WrapperProps) => (
|
|
94
|
+
<svg
|
|
95
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
96
|
+
fill="none"
|
|
97
|
+
viewBox="0 0 24 24"
|
|
98
|
+
{...wrapperProps(props)}
|
|
99
|
+
>
|
|
100
|
+
<title>{'JavaScript'}</title>
|
|
101
|
+
<path
|
|
102
|
+
fill="#F59E0B"
|
|
103
|
+
d="M8.383 7.318h2.127v7.1c0 .656-.147 1.226-.442 1.71a2.924 2.924 0 01-1.218 1.118c-.52.262-1.125.393-1.815.393-.613 0-1.17-.107-1.67-.323a2.67 2.67 0 01-1.183-.994c-.292-.448-.436-1.01-.433-1.686h2.143c.006.269.061.5.164.691.106.19.25.335.432.438.186.1.405.15.657.15.265 0 .488-.057.67-.17.186-.116.327-.285.423-.507.096-.222.145-.496.145-.82v-7.1zm9.43 2.928c-.04-.4-.21-.712-.511-.934-.302-.222-.711-.333-1.228-.333-.352 0-.648.05-.89.149-.242.096-.428.23-.557.403a.969.969 0 00-.19.586.838.838 0 00.115.477c.087.136.204.254.353.353.15.097.322.181.517.254.196.07.405.13.627.179l.915.219c.444.1.851.232 1.223.397.37.166.692.37.964.612s.482.527.631.855a2.7 2.7 0 01.234 1.129c-.003.623-.162 1.163-.477 1.62-.312.454-.763.807-1.353 1.06-.586.248-1.294.372-2.122.372-.822 0-1.538-.126-2.148-.378-.607-.252-1.08-.624-1.422-1.118-.338-.497-.515-1.112-.532-1.845h2.083c.023.342.121.627.293.855.176.226.41.397.702.513.295.112.628.168.999.168.364 0 .68-.053.95-.159.271-.106.482-.253.63-.442.15-.189.224-.406.224-.651a.846.846 0 00-.203-.577c-.133-.156-.329-.288-.587-.398a5.964 5.964 0 00-.94-.298l-1.108-.278c-.859-.21-1.537-.536-2.034-.98-.497-.444-.744-1.042-.74-1.795-.004-.616.16-1.155.492-1.615.334-.461.793-.82 1.377-1.08.583-.258 1.246-.387 1.989-.387.755 0 1.415.13 1.978.388.567.258 1.008.618 1.323 1.079.314.46.477.994.487 1.6h-2.063z"
|
|
104
|
+
></path>
|
|
105
|
+
</svg>
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
export const Json = (props: WrapperProps) => (
|
|
109
|
+
<svg
|
|
110
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
111
|
+
fill="none"
|
|
112
|
+
viewBox="0 0 24 24"
|
|
113
|
+
{...wrapperProps(props)}
|
|
114
|
+
>
|
|
115
|
+
<title>{'JSON'}</title>
|
|
116
|
+
<path
|
|
117
|
+
fill="#F59E0B"
|
|
118
|
+
d="M4.778 6.667A2.667 2.667 0 017.444 4a.889.889 0 010 1.778.889.889 0 00-.888.889v3.5c0 .701-.273 1.35-.73 1.833.457.483.73 1.132.73 1.832v3.501c0 .491.398.89.888.89a.889.889 0 010 1.777 2.667 2.667 0 01-2.666-2.667v-3.5a.889.889 0 00-.674-.863l-.43-.108a.889.889 0 010-1.724l.43-.108a.889.889 0 00.674-.862V6.667zm14.222 0A2.667 2.667 0 0016.333 4a.889.889 0 000 1.778c.491 0 .89.398.89.889v3.5c0 .701.272 1.35.729 1.833a2.664 2.664 0 00-.73 1.832v3.501a.889.889 0 01-.889.89.889.889 0 000 1.777A2.667 2.667 0 0019 17.333v-3.5c0-.408.278-.764.673-.863l.431-.108a.889.889 0 000-1.724l-.43-.108a.889.889 0 01-.674-.862V6.667z"
|
|
119
|
+
></path>
|
|
120
|
+
</svg>
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
export const Css = (props: WrapperProps) => (
|
|
124
|
+
<svg
|
|
125
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
126
|
+
fill="none"
|
|
127
|
+
viewBox="0 0 24 24"
|
|
128
|
+
{...wrapperProps(props)}
|
|
129
|
+
>
|
|
130
|
+
<title>{'CSS'}</title>
|
|
131
|
+
<path
|
|
132
|
+
fill="#0EA5E9"
|
|
133
|
+
d="M4.778 6.667A2.667 2.667 0 017.444 4a.889.889 0 010 1.778.889.889 0 00-.888.889v3.5c0 .701-.273 1.35-.73 1.833.457.483.73 1.132.73 1.832v3.501c0 .491.398.89.888.89a.889.889 0 010 1.777 2.667 2.667 0 01-2.666-2.667v-3.5a.889.889 0 00-.674-.863l-.43-.108a.889.889 0 010-1.724l.43-.108a.889.889 0 00.674-.862V6.667zm14.222 0A2.667 2.667 0 0016.333 4a.889.889 0 000 1.778c.491 0 .89.398.89.889v3.5c0 .701.272 1.35.729 1.833a2.664 2.664 0 00-.73 1.832v3.501a.889.889 0 01-.889.89.889.889 0 000 1.777A2.667 2.667 0 0019 17.333v-3.5c0-.408.278-.764.673-.863l.431-.108a.889.889 0 000-1.724l-.43-.108a.889.889 0 01-.674-.862V6.667z"
|
|
134
|
+
></path>
|
|
135
|
+
</svg>
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
export const BracketsOrange = (props: WrapperProps) => (
|
|
139
|
+
<svg
|
|
140
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
141
|
+
fill="none"
|
|
142
|
+
viewBox="0 0 24 24"
|
|
143
|
+
{...wrapperProps(props)}
|
|
144
|
+
>
|
|
145
|
+
<title>{'HTML'}</title>
|
|
146
|
+
<path
|
|
147
|
+
fill="#EA580C"
|
|
148
|
+
d="M4.778 6.667A2.667 2.667 0 017.444 4a.889.889 0 010 1.778.889.889 0 00-.888.889v3.5c0 .701-.273 1.35-.73 1.833.457.483.73 1.132.73 1.832v3.501c0 .491.398.89.888.89a.889.889 0 010 1.777 2.667 2.667 0 01-2.666-2.667v-3.5a.889.889 0 00-.674-.863l-.43-.108a.889.889 0 010-1.724l.43-.108a.889.889 0 00.674-.862V6.667zm14.222 0A2.667 2.667 0 0016.333 4a.889.889 0 000 1.778c.491 0 .89.398.89.889v3.5c0 .701.272 1.35.729 1.833a2.664 2.664 0 00-.73 1.832v3.501a.889.889 0 01-.889.89.889.889 0 000 1.777A2.667 2.667 0 0019 17.333v-3.5c0-.408.278-.764.673-.863l.431-.108a.889.889 0 000-1.724l-.43-.108a.889.889 0 01-.674-.862V6.667z"
|
|
149
|
+
></path>
|
|
150
|
+
</svg>
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
export default BracketsOrange
|
|
154
|
+
|
|
155
|
+
export const React = (props: WrapperProps) => (
|
|
156
|
+
<svg
|
|
157
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
158
|
+
fill="none"
|
|
159
|
+
viewBox="0 0 24 24"
|
|
160
|
+
{...wrapperProps(props)}
|
|
161
|
+
>
|
|
162
|
+
<title>{'React'}</title>
|
|
163
|
+
<path
|
|
164
|
+
fill="#0E8ADC"
|
|
165
|
+
d="M12 13.677a1.677 1.677 0 100-3.354 1.677 1.677 0 000 3.354z"
|
|
166
|
+
></path>
|
|
167
|
+
<path
|
|
168
|
+
stroke="#0E8ADC"
|
|
169
|
+
d="M12 15.436c4.97 0 9-1.538 9-3.436s-4.03-3.436-9-3.436S3 10.102 3 12s4.03 3.436 9 3.436z"
|
|
170
|
+
></path>
|
|
171
|
+
<path
|
|
172
|
+
stroke="#0E8ADC"
|
|
173
|
+
d="M9.024 13.718c2.485 4.305 5.832 7.025 7.476 6.076 1.644-.949.961-5.208-1.524-9.512C12.491 5.977 9.144 3.257 7.5 4.206c-1.644.949-.961 5.208 1.524 9.512z"
|
|
174
|
+
></path>
|
|
175
|
+
<path
|
|
176
|
+
stroke="#0E8ADC"
|
|
177
|
+
d="M9.024 10.282c-2.485 4.304-3.168 8.563-1.524 9.512 1.644.95 4.99-1.771 7.476-6.076 2.485-4.304 3.168-8.563 1.524-9.512-1.644-.95-4.99 1.771-7.476 6.076z"
|
|
178
|
+
></path>
|
|
179
|
+
</svg>
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
export const Markdown = (props: WrapperProps) => (
|
|
183
|
+
<svg
|
|
184
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
185
|
+
fill="none"
|
|
186
|
+
viewBox="0 0 24 24"
|
|
187
|
+
{...wrapperProps(props)}
|
|
188
|
+
>
|
|
189
|
+
<title>{'Markdown'}</title>
|
|
190
|
+
<path
|
|
191
|
+
fill="#60A5FA"
|
|
192
|
+
d="M3 15.714V8h2.323l2.322 2.836L9.968 8h2.322v7.714H9.968V11.29l-2.323 2.836-2.322-2.836v4.424H3zm14.516 0l-3.484-3.743h2.323V8h2.322v3.97H21l-3.484 3.744z"
|
|
193
|
+
></path>
|
|
194
|
+
</svg>
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
export const Shell = (props: WrapperProps) => (
|
|
198
|
+
<svg
|
|
199
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
200
|
+
fill="none"
|
|
201
|
+
viewBox="0 0 25 24"
|
|
202
|
+
{...wrapperProps(props)}
|
|
203
|
+
>
|
|
204
|
+
<title>{'Shell'}</title>
|
|
205
|
+
<path
|
|
206
|
+
stroke="#14B8A6"
|
|
207
|
+
strokeLinecap="round"
|
|
208
|
+
strokeLinejoin="round"
|
|
209
|
+
strokeWidth="2"
|
|
210
|
+
d="M4.336 17l6-6-6-6M12.336 19h8"
|
|
211
|
+
></path>
|
|
212
|
+
</svg>
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
export const Yaml = (props: WrapperProps) => (
|
|
216
|
+
<svg
|
|
217
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
218
|
+
fill="none"
|
|
219
|
+
viewBox="0 0 24 24"
|
|
220
|
+
{...wrapperProps(props)}
|
|
221
|
+
>
|
|
222
|
+
<title>{'YAML'}</title>
|
|
223
|
+
<path
|
|
224
|
+
fill="#A78BFA"
|
|
225
|
+
d="M6.533 5.864h2.755l2.654 5.011h.113l2.654-5.011h2.756l-4.245 7.522V17.5h-2.443v-4.114L6.533 5.864z"
|
|
226
|
+
></path>
|
|
227
|
+
</svg>
|
|
228
|
+
)
|
|
@@ -1,11 +1,38 @@
|
|
|
1
1
|
import * as RAC from 'react-aria-components'
|
|
2
|
-
import { Copy, Check } from 'lucide-react'
|
|
2
|
+
import { Copy, Check, File } from 'lucide-react'
|
|
3
3
|
import { cn } from '@client/utils/cn'
|
|
4
4
|
import { useCodeBlock } from './hooks/use-code-block'
|
|
5
5
|
import { useConfig } from '@client/app/config-context'
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
CodeSandbox,
|
|
8
|
+
TypeScript,
|
|
9
|
+
JavaScript,
|
|
10
|
+
React as ReactIcon,
|
|
11
|
+
Json,
|
|
12
|
+
Css,
|
|
13
|
+
BracketsOrange,
|
|
14
|
+
Markdown,
|
|
15
|
+
Shell,
|
|
16
|
+
Yaml,
|
|
17
|
+
} from '@components/icons-dev'
|
|
7
18
|
import { Tooltip } from '@components/primitives/tooltip'
|
|
8
19
|
|
|
20
|
+
const langIconMap: Record<string, React.ComponentType<{ size?: number }>> = {
|
|
21
|
+
ts: TypeScript,
|
|
22
|
+
tsx: ReactIcon,
|
|
23
|
+
js: JavaScript,
|
|
24
|
+
jsx: ReactIcon,
|
|
25
|
+
json: Json,
|
|
26
|
+
css: Css,
|
|
27
|
+
html: BracketsOrange,
|
|
28
|
+
md: Markdown,
|
|
29
|
+
mdx: Markdown,
|
|
30
|
+
bash: Shell,
|
|
31
|
+
sh: Shell,
|
|
32
|
+
yaml: Yaml,
|
|
33
|
+
yml: Yaml,
|
|
34
|
+
}
|
|
35
|
+
|
|
9
36
|
export interface CodeBlockProps {
|
|
10
37
|
children?: React.ReactNode
|
|
11
38
|
className?: string
|
|
@@ -15,6 +42,8 @@ export interface CodeBlockProps {
|
|
|
15
42
|
title?: string
|
|
16
43
|
lang?: string
|
|
17
44
|
highlightedHtml?: string
|
|
45
|
+
'data-lang'?: string
|
|
46
|
+
plain?: boolean
|
|
18
47
|
[key: string]: any
|
|
19
48
|
}
|
|
20
49
|
|
|
@@ -25,11 +54,15 @@ export function CodeBlock(props: CodeBlockProps) {
|
|
|
25
54
|
hideSandbox = true,
|
|
26
55
|
hideCopy = false,
|
|
27
56
|
highlightedHtml,
|
|
57
|
+
title,
|
|
58
|
+
'data-lang': dataLang,
|
|
59
|
+
plain = false,
|
|
28
60
|
...rest
|
|
29
61
|
} = props
|
|
30
62
|
const config = useConfig()
|
|
31
63
|
const globalSandbox = config?.integrations?.sandbox
|
|
32
64
|
const isSandboxEnabled = !!globalSandbox?.enable && !hideSandbox
|
|
65
|
+
const lang = props.lang || dataLang || ''
|
|
33
66
|
const {
|
|
34
67
|
copied,
|
|
35
68
|
isExpanded,
|
|
@@ -41,13 +74,32 @@ export function CodeBlock(props: CodeBlockProps) {
|
|
|
41
74
|
shouldTruncate,
|
|
42
75
|
} = useCodeBlock(props)
|
|
43
76
|
|
|
77
|
+
const LangIcon = langIconMap[lang]
|
|
78
|
+
|
|
44
79
|
return (
|
|
45
80
|
<div
|
|
46
81
|
className={cn(
|
|
47
|
-
'group relative
|
|
48
|
-
|
|
82
|
+
'group relative overflow-hidden bg-(--color-code-bg)',
|
|
83
|
+
'contain-layout contain-paint', // Optimization: isolate code block rendering
|
|
84
|
+
{
|
|
85
|
+
'my-6 rounded-lg border border-border-subtle': !plain,
|
|
86
|
+
'[&>pre]:max-h-62.5 [&>pre]:overflow-hidden': shouldTruncate,
|
|
87
|
+
},
|
|
88
|
+
props.className,
|
|
49
89
|
)}
|
|
50
90
|
>
|
|
91
|
+
{/* Title Header */}
|
|
92
|
+
{title && (
|
|
93
|
+
<div className="flex items-center gap-2 border-b border-border-subtle bg-bg-surface/50 px-4 py-2 text-[13px] font-medium text-text-muted">
|
|
94
|
+
{LangIcon ? (
|
|
95
|
+
<LangIcon size={14} />
|
|
96
|
+
) : (
|
|
97
|
+
<File size={14} className="opacity-60" />
|
|
98
|
+
)}
|
|
99
|
+
<span>{title}</span>
|
|
100
|
+
</div>
|
|
101
|
+
)}
|
|
102
|
+
|
|
51
103
|
{/* Toolbar */}
|
|
52
104
|
<div className="absolute top-3 right-4 z-50 flex items-center gap-2 transition-all duration-300 opacity-0 group-hover:opacity-100">
|
|
53
105
|
{isSandboxEnabled && (
|
|
@@ -66,7 +118,7 @@ export function CodeBlock(props: CodeBlockProps) {
|
|
|
66
118
|
<RAC.Button
|
|
67
119
|
onPress={handleCopy}
|
|
68
120
|
className={cn(
|
|
69
|
-
'grid place-items-center
|
|
121
|
+
'grid place-items-center size-8 bg-transparent outline-none cursor-pointer transition-all duration-200 hover:scale-110 active:scale-95 [&>svg]:size-4 [&>svg]:stroke-2',
|
|
70
122
|
copied
|
|
71
123
|
? 'text-emerald-400'
|
|
72
124
|
: 'text-text-muted hover:text-text-main',
|
|
@@ -10,11 +10,39 @@ import {
|
|
|
10
10
|
} from 'lucide-react'
|
|
11
11
|
import { cn } from '@client/utils/cn'
|
|
12
12
|
|
|
13
|
+
import {
|
|
14
|
+
TypeScript,
|
|
15
|
+
JavaScript,
|
|
16
|
+
React as ReactIcon,
|
|
17
|
+
Json,
|
|
18
|
+
Css,
|
|
19
|
+
BracketsOrange,
|
|
20
|
+
Markdown,
|
|
21
|
+
Shell,
|
|
22
|
+
Yaml,
|
|
23
|
+
} from '@components/icons-dev'
|
|
24
|
+
|
|
13
25
|
// --- Constants & Types ---
|
|
14
26
|
|
|
15
27
|
const ICON_SIZE = 16
|
|
16
28
|
const STROKE_WIDTH = 2
|
|
17
29
|
|
|
30
|
+
const FILE_EXTENSION_MAP: Record<string, React.ComponentType<{ size?: number }>> = {
|
|
31
|
+
ts: TypeScript,
|
|
32
|
+
tsx: ReactIcon,
|
|
33
|
+
js: JavaScript,
|
|
34
|
+
jsx: ReactIcon,
|
|
35
|
+
json: Json,
|
|
36
|
+
css: Css,
|
|
37
|
+
html: BracketsOrange,
|
|
38
|
+
md: Markdown,
|
|
39
|
+
mdx: Markdown,
|
|
40
|
+
bash: Shell,
|
|
41
|
+
sh: Shell,
|
|
42
|
+
yaml: Yaml,
|
|
43
|
+
yml: Yaml,
|
|
44
|
+
}
|
|
45
|
+
|
|
18
46
|
const FILE_REGEXES = {
|
|
19
47
|
CODE: /\.(ts|tsx|js|jsx|json|mjs|cjs|astro|vue|svelte)$/i,
|
|
20
48
|
TEXT: /\.(md|mdx|txt)$/i,
|
|
@@ -68,6 +96,13 @@ function getFileIcon(filename: string, isFolder: boolean) {
|
|
|
68
96
|
)
|
|
69
97
|
}
|
|
70
98
|
|
|
99
|
+
// Check for specialized language icons
|
|
100
|
+
const extension = name.split('.').pop() || ''
|
|
101
|
+
const LangIcon = FILE_EXTENSION_MAP[extension]
|
|
102
|
+
if (LangIcon) {
|
|
103
|
+
return <LangIcon size={ICON_SIZE} />
|
|
104
|
+
}
|
|
105
|
+
|
|
71
106
|
const fileIconClass = cn(
|
|
72
107
|
iconClass,
|
|
73
108
|
'text-text-dim group-hover:text-text-main',
|
|
@@ -14,51 +14,42 @@ export class Observer {
|
|
|
14
14
|
private callback(entries: IntersectionObserverEntry[]) {
|
|
15
15
|
if (entries.length === 0) return
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
item
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
17
|
+
// 1. Update internal state based on current intersection and position
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
const item = this.items.find((i) => i.id === entry.target.id)
|
|
20
|
+
if (item) {
|
|
21
|
+
// item.active will track if the heading is currently "on or below" the trigger line
|
|
22
|
+
item.active = entry.isIntersecting
|
|
23
|
+
|
|
24
|
+
// item.fallback will track if the heading has scrolled "above" the trigger line
|
|
25
|
+
// RootMargin top is -100px, so trigger line is at 100px.
|
|
26
|
+
const activationLine = 100
|
|
27
|
+
item.fallback =
|
|
28
|
+
!entry.isIntersecting && entry.boundingClientRect.top < activationLine
|
|
30
29
|
}
|
|
30
|
+
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
let min = Number.MAX_VALUE
|
|
39
|
-
let fallbackIdx = -1
|
|
40
|
-
|
|
41
|
-
for (let i = 0; i < this.items.length; i++) {
|
|
42
|
-
const element = document.getElementById(this.items[i].id)
|
|
43
|
-
if (!element) continue
|
|
44
|
-
|
|
45
|
-
const d = Math.abs(viewTop - element.getBoundingClientRect().top)
|
|
46
|
-
if (d < min) {
|
|
47
|
-
fallbackIdx = i
|
|
48
|
-
min = d
|
|
49
|
-
}
|
|
32
|
+
// 2. The active heading is the LAST one in document order that has scrolled past the line.
|
|
33
|
+
let highlightIdx = -1
|
|
34
|
+
for (let i = this.items.length - 1; i >= 0; i--) {
|
|
35
|
+
if (this.items[i].fallback) {
|
|
36
|
+
highlightIdx = i
|
|
37
|
+
break
|
|
50
38
|
}
|
|
39
|
+
}
|
|
51
40
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
active: true,
|
|
56
|
-
fallback: true,
|
|
57
|
-
t: Date.now(),
|
|
58
|
-
}
|
|
59
|
-
}
|
|
41
|
+
// 3. Initial state: If no headings have passed the line yet, default to the first heading.
|
|
42
|
+
if (highlightIdx === -1 && this.items.length > 0) {
|
|
43
|
+
highlightIdx = 0
|
|
60
44
|
}
|
|
61
45
|
|
|
46
|
+
// 4. Map back to UI state
|
|
47
|
+
this.items = this.items.map((item, idx) => ({
|
|
48
|
+
...item,
|
|
49
|
+
active: idx === highlightIdx,
|
|
50
|
+
t: idx === highlightIdx ? Date.now() : item.t,
|
|
51
|
+
}))
|
|
52
|
+
|
|
62
53
|
this.onChange?.()
|
|
63
54
|
}
|
|
64
55
|
|
|
@@ -20,7 +20,7 @@ export function MenuTrigger(props: MenuTriggerProps) {
|
|
|
20
20
|
return (
|
|
21
21
|
<RAC.MenuTrigger {...props}>
|
|
22
22
|
{trigger as any}
|
|
23
|
-
<Popover placement={props.placement} className="min-w-
|
|
23
|
+
<Popover placement={props.placement} className="min-w-35">
|
|
24
24
|
{menu as any}
|
|
25
25
|
</Popover>
|
|
26
26
|
</RAC.MenuTrigger>
|
|
@@ -52,7 +52,10 @@ export function Menu<T extends object>(props: RAC.MenuProps<T>) {
|
|
|
52
52
|
<RAC.Menu
|
|
53
53
|
{...props}
|
|
54
54
|
className={RAC.composeRenderProps(props.className, (className) =>
|
|
55
|
-
cn(
|
|
55
|
+
cn(
|
|
56
|
+
'p-1.5 outline-none max-h-[inherit] overflow-auto max-w-75',
|
|
57
|
+
className,
|
|
58
|
+
),
|
|
56
59
|
)}
|
|
57
60
|
/>
|
|
58
61
|
)
|
|
@@ -74,11 +77,14 @@ export function MenuItem(props: RAC.MenuItemProps) {
|
|
|
74
77
|
props.className,
|
|
75
78
|
(className, { isFocused, isPressed, isDisabled }) =>
|
|
76
79
|
cn(
|
|
77
|
-
'group relative flex flex-row items-center gap-2
|
|
78
|
-
'text-text-main text-[
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
'group relative flex flex-row items-center gap-2 px-2 py-1 rounded-lg outline-none cursor-default hover:cursor-pointer transition-none',
|
|
81
|
+
'text-text-main text-[12px]',
|
|
82
|
+
{
|
|
83
|
+
'bg-bg-surface-elevated text-primary-600 ring-1 ring-border-strong/5':
|
|
84
|
+
isFocused,
|
|
85
|
+
'bg-bg-surface-elevanted': isPressed,
|
|
86
|
+
'opacity-40 grayscale pointer-events-none': isDisabled,
|
|
87
|
+
},
|
|
82
88
|
className,
|
|
83
89
|
),
|
|
84
90
|
)}
|
|
@@ -88,20 +94,20 @@ export function MenuItem(props: RAC.MenuItemProps) {
|
|
|
88
94
|
(children, { selectionMode, isSelected, hasSubmenu }) => (
|
|
89
95
|
<>
|
|
90
96
|
{selectionMode !== 'none' && (
|
|
91
|
-
<span className="flex items-center
|
|
97
|
+
<span className="flex items-center size-4 shrink-0 justify-center">
|
|
92
98
|
{isSelected && selectionMode === 'multiple' && (
|
|
93
|
-
<Check className="
|
|
99
|
+
<Check className="size-3.5 stroke-[2.5px] text-primary-500 animate-in zoom-in-50 duration-200" />
|
|
94
100
|
)}
|
|
95
101
|
{isSelected && selectionMode === 'single' && (
|
|
96
|
-
<Dot className="
|
|
102
|
+
<Dot className="size-5 text-primary-500 animate-in zoom-in-50 duration-200" />
|
|
97
103
|
)}
|
|
98
104
|
</span>
|
|
99
105
|
)}
|
|
100
|
-
<div className="flex
|
|
106
|
+
<div className="flex flex-row w-full transition-colors items-center gap-2 py-1 px-1">
|
|
101
107
|
{children}
|
|
102
108
|
</div>
|
|
103
109
|
{hasSubmenu && (
|
|
104
|
-
<ChevronRight className="
|
|
110
|
+
<ChevronRight className="size-4 ml-auto text-text-muted group-focused:text-primary-500/70 transition-colors" />
|
|
105
111
|
)}
|
|
106
112
|
</>
|
|
107
113
|
),
|
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
import { type ReactNode, useState, useEffect } from 'react'
|
|
2
|
-
import {
|
|
3
|
-
Button,
|
|
4
|
-
Separator,
|
|
5
|
-
ToggleButton,
|
|
6
|
-
Link,
|
|
7
|
-
Menu,
|
|
8
|
-
MenuItem,
|
|
9
|
-
MenuTrigger,
|
|
10
|
-
cn,
|
|
11
|
-
} from './index'
|
|
2
|
+
import { Separator, ToggleButton, Link, cn } from './index'
|
|
12
3
|
import { Button as ButtonRAC } from 'react-aria-components'
|
|
13
|
-
import { Search, Sun, Moon, ExternalLink
|
|
4
|
+
import { Search, Sun, Moon, ExternalLink } from 'lucide-react'
|
|
14
5
|
import * as IconsSocials from '@components/icons-dev'
|
|
15
6
|
import type { ComponentBase } from './types'
|
|
16
7
|
import type { BoltdocsSocialLink } from '@node/config'
|
|
@@ -39,21 +30,6 @@ export interface NavbarThemeProps {
|
|
|
39
30
|
onThemeChange: (isSelected: boolean) => void
|
|
40
31
|
}
|
|
41
32
|
|
|
42
|
-
export interface NavbarMenuProps extends ComponentBase {
|
|
43
|
-
label: ReactNode
|
|
44
|
-
icon?: ReactNode
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface NavbarVersionProps extends ComponentBase {
|
|
48
|
-
current: string
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface NavbarItemProps extends Omit<ComponentBase, 'children'> {
|
|
52
|
-
label: string
|
|
53
|
-
onPress?: () => void
|
|
54
|
-
isCurrent?: boolean
|
|
55
|
-
}
|
|
56
|
-
|
|
57
33
|
export interface NavbarSocialsProps extends ComponentBase {
|
|
58
34
|
icon: string
|
|
59
35
|
link: string
|
|
@@ -92,13 +68,25 @@ export const NavbarContent = ({ children, className }: ComponentBase) => {
|
|
|
92
68
|
|
|
93
69
|
export const NavbarLeft = ({ children, className }: ComponentBase) => {
|
|
94
70
|
return (
|
|
95
|
-
<div
|
|
71
|
+
<div
|
|
72
|
+
className={cn(
|
|
73
|
+
'flex flex-1 items-center justify-start gap-4 min-w-0',
|
|
74
|
+
className,
|
|
75
|
+
)}
|
|
76
|
+
>
|
|
77
|
+
{children}
|
|
78
|
+
</div>
|
|
96
79
|
)
|
|
97
80
|
}
|
|
98
81
|
|
|
99
82
|
export const NavbarRight = ({ children, className }: ComponentBase) => {
|
|
100
83
|
return (
|
|
101
|
-
<div
|
|
84
|
+
<div
|
|
85
|
+
className={cn(
|
|
86
|
+
'flex flex-1 items-center justify-end gap-2 md:gap-4 min-w-0',
|
|
87
|
+
className,
|
|
88
|
+
)}
|
|
89
|
+
>
|
|
102
90
|
{children}
|
|
103
91
|
</div>
|
|
104
92
|
)
|
|
@@ -108,7 +96,7 @@ export const NavbarCenter = ({ children, className }: ComponentBase) => {
|
|
|
108
96
|
return (
|
|
109
97
|
<div
|
|
110
98
|
className={cn(
|
|
111
|
-
'hidden lg:flex flex-1 justify-center items-center gap-4 px-4',
|
|
99
|
+
'hidden lg:flex flex-1 justify-center items-center gap-4 px-4 min-w-0 w-full',
|
|
112
100
|
className,
|
|
113
101
|
)}
|
|
114
102
|
>
|
|
@@ -144,14 +132,16 @@ export const NavbarLogo = ({
|
|
|
144
132
|
|
|
145
133
|
export const NavbarTitle = ({ children, className }: ComponentBase) => {
|
|
146
134
|
return (
|
|
147
|
-
<
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
135
|
+
<Link href="/">
|
|
136
|
+
<span
|
|
137
|
+
className={cn(
|
|
138
|
+
'text-lg font-bold tracking-tight hidden sm:inline-block',
|
|
139
|
+
className,
|
|
140
|
+
)}
|
|
141
|
+
>
|
|
142
|
+
{children}
|
|
143
|
+
</span>
|
|
144
|
+
</Link>
|
|
155
145
|
)
|
|
156
146
|
}
|
|
157
147
|
|
|
@@ -180,10 +170,10 @@ export const NavbarLink = ({
|
|
|
180
170
|
href={href}
|
|
181
171
|
target={to === 'external' ? '_blank' : undefined}
|
|
182
172
|
className={cn(
|
|
183
|
-
'transition-colors outline-none focus-visible:ring-2 focus-visible:ring-primary-500/30 rounded-sm',
|
|
173
|
+
'transition-colors outline-none font-medium focus-visible:ring-2 focus-visible:ring-primary-500/30 rounded-sm',
|
|
184
174
|
{
|
|
185
|
-
'text-primary-500
|
|
186
|
-
'text-text-muted hover:text-text-main
|
|
175
|
+
'text-primary-500': active,
|
|
176
|
+
'text-text-muted hover:text-text-main': !active,
|
|
187
177
|
},
|
|
188
178
|
className,
|
|
189
179
|
)}
|
|
@@ -216,7 +206,7 @@ export const NavbarSearchTrigger = ({
|
|
|
216
206
|
'flex items-center gap-2 rounded-full border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-muted outline-none cursor-pointer',
|
|
217
207
|
'transition-all duration-200 hover:border-border-strong hover:text-text-main hover:bg-bg-muted hover:shadow-sm active:scale-[0.98]',
|
|
218
208
|
'focus-visible:ring-2 focus-visible:ring-primary-500/30',
|
|
219
|
-
'w-full max-w-[
|
|
209
|
+
'w-full max-w-[720px] justify-between',
|
|
220
210
|
className,
|
|
221
211
|
)}
|
|
222
212
|
>
|
|
@@ -258,54 +248,6 @@ export const NavbarTheme = ({
|
|
|
258
248
|
)
|
|
259
249
|
}
|
|
260
250
|
|
|
261
|
-
export const NavbarMenu = ({
|
|
262
|
-
label,
|
|
263
|
-
children,
|
|
264
|
-
className,
|
|
265
|
-
icon,
|
|
266
|
-
}: NavbarMenuProps) => {
|
|
267
|
-
return (
|
|
268
|
-
<MenuTrigger placement="bottom end">
|
|
269
|
-
<Button
|
|
270
|
-
variant="ghost"
|
|
271
|
-
className={cn(
|
|
272
|
-
'flex items-center gap-1.5 rounded-md px-3 py-1.5 text-text-muted outline-none cursor-pointer transition-colors',
|
|
273
|
-
'hover:bg-bg-surface hover:text-text-main',
|
|
274
|
-
'focus-visible:ring-2 focus-visible:ring-primary-500/30',
|
|
275
|
-
className,
|
|
276
|
-
)}
|
|
277
|
-
>
|
|
278
|
-
{icon && <span className="flex items-center shrink-0">{icon}</span>}
|
|
279
|
-
<span className="text-[13px] font-bold uppercase tracking-wide">
|
|
280
|
-
{label}
|
|
281
|
-
</span>
|
|
282
|
-
<ChevronDown size={14} className="ml-0.5 opacity-50" />
|
|
283
|
-
</Button>
|
|
284
|
-
<Menu className="min-w-[180px]">{children as any}</Menu>
|
|
285
|
-
</MenuTrigger>
|
|
286
|
-
)
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
export const NavbarItem = ({
|
|
290
|
-
label,
|
|
291
|
-
className,
|
|
292
|
-
onPress,
|
|
293
|
-
isCurrent,
|
|
294
|
-
}: NavbarItemProps) => {
|
|
295
|
-
return (
|
|
296
|
-
<MenuItem
|
|
297
|
-
onAction={onPress}
|
|
298
|
-
className={cn(
|
|
299
|
-
isCurrent &&
|
|
300
|
-
'bg-primary-500 text-white font-medium hover:bg-primary-600 focus:bg-primary-600 focus:text-white',
|
|
301
|
-
className,
|
|
302
|
-
)}
|
|
303
|
-
>
|
|
304
|
-
{label}
|
|
305
|
-
</MenuItem>
|
|
306
|
-
)
|
|
307
|
-
}
|
|
308
|
-
|
|
309
251
|
export const Icon = ({ name }: { name: BoltdocsSocialLink['icon'] }) => {
|
|
310
252
|
if (name === 'github') return <IconsSocials.Github />
|
|
311
253
|
if (name === 'discord') return <IconsSocials.Discord />
|
|
@@ -355,7 +297,6 @@ export default {
|
|
|
355
297
|
Link: NavbarLink,
|
|
356
298
|
SearchTrigger: NavbarSearchTrigger,
|
|
357
299
|
Theme: NavbarTheme,
|
|
358
|
-
Item: NavbarItem,
|
|
359
300
|
Socials: NavbarSocials,
|
|
360
301
|
Split: NavbarSplit,
|
|
361
302
|
Content: NavbarContent,
|