@graphcommerce/docs 3.1.4 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/{content/framework → framework}/deployment.md +10 -6
- package/{content/framework → framework}/environment-variables.md +0 -0
- package/{content/framework → framework}/favicon.md +3 -1
- package/{content/framework → framework}/graphcms.md +10 -4
- package/{content/framework → framework}/icons.md +0 -0
- package/{content/framework → framework}/readme.md +0 -0
- package/{content/framework → framework}/seo.md +0 -0
- package/{content/framework → framework}/static-file-serving.md +0 -0
- package/{content/framework → framework}/static-generation.md +0 -0
- package/{content/framework → framework}/theming.md +1 -1
- package/{content/framework → framework}/translations.md +3 -1
- package/{content/framework → framework}/troubleshooting.md +0 -0
- package/{content/framework → framework}/typography.md +0 -0
- package/{content/getting-started → getting-started}/create.md +7 -3
- package/{content/getting-started → getting-started}/graphcms-component.md +30 -10
- package/{content/getting-started → getting-started}/header.md +17 -7
- package/{content/getting-started → getting-started}/pages.md +12 -4
- package/{content/getting-started → getting-started}/readme.md +3 -2
- package/{content/getting-started → getting-started}/start-building.md +2 -2
- package/{content/getting-started → getting-started}/vscode.md +0 -0
- package/package.json +6 -51
- package/{content/readme.md → readme.md} +1 -1
- package/{content/roadmap.md → roadmap.md} +0 -0
- package/.babelrc +0 -4
- package/components/Layout/LayoutFull.tsx +0 -85
- package/components/Layout/Logo.tsx +0 -19
- package/components/Layout/graphcommerce.svg +0 -34
- package/components/Search.tsx +0 -37
- package/components/SearchForm.tsx +0 -110
- package/components/SidebarMenu/index.tsx +0 -101
- package/components/prism.css +0 -274
- package/components/rehype-prism-plus.css +0 -49
- package/components/theme.ts +0 -410
- package/lib/DocumentIndexer.ts +0 -59
- package/lib/files.ts +0 -168
- package/lib/instantSearch.ts +0 -26
- package/lib/typesense/IndexerHandler.ts +0 -47
- package/lib/typesense/Leaves.ts +0 -37
- package/lib/typesense/SearchIndexer.ts +0 -64
- package/lib/typesense/batchInterable.ts +0 -13
- package/lib/typesense/createInstantSearchProps.ts +0 -36
- package/lib/typesense/typesenseClientConf.ts +0 -23
- package/lib/typesense/typesenseIndexerHandler.ts +0 -23
- package/next-env.d.ts +0 -5
- package/next.config.js +0 -21
- package/pages/[[...url]].tsx +0 -391
- package/pages/_app.tsx +0 -26
- package/pages/_document.tsx +0 -22
- package/pages/api/reindex.ts +0 -4
- package/pages/menu/[[...url]].tsx +0 -69
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/favicon.svg +0 -12
- package/public/link.svg +0 -4
- package/public/manifest/favicon-192.png +0 -0
- package/public/manifest/favicon-512.png +0 -0
- package/public/manifest.webmanifest +0 -20
package/components/theme.ts
DELETED
|
@@ -1,410 +0,0 @@
|
|
|
1
|
-
/// <reference types="@graphcommerce/next-ui/types" />
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
responsiveVal,
|
|
5
|
-
breakpointVal,
|
|
6
|
-
MuiButtonPill,
|
|
7
|
-
MuiButtonResponsive,
|
|
8
|
-
themeBaseDefaults,
|
|
9
|
-
MuiSnackbar,
|
|
10
|
-
MuiFabSizes,
|
|
11
|
-
} from '@graphcommerce/next-ui'
|
|
12
|
-
import { createTheme, Theme, alpha, darken, lighten } from '@mui/material'
|
|
13
|
-
import { Components, PaletteOptions } from '@mui/material/styles'
|
|
14
|
-
|
|
15
|
-
const main = '#85FFFD'
|
|
16
|
-
const dark = '#CEFF99'
|
|
17
|
-
|
|
18
|
-
const lightPalette: PaletteOptions = {
|
|
19
|
-
mode: 'light',
|
|
20
|
-
primary: {
|
|
21
|
-
main: darken(main, 0.175),
|
|
22
|
-
contrastText: '#FFFFFF',
|
|
23
|
-
dark: darken(dark, 0.175),
|
|
24
|
-
},
|
|
25
|
-
secondary: {
|
|
26
|
-
main: '#006BFF',
|
|
27
|
-
light: '#D1E4FF',
|
|
28
|
-
contrastText: '#ffffff',
|
|
29
|
-
},
|
|
30
|
-
background: {
|
|
31
|
-
default: '#ffffff',
|
|
32
|
-
paper: '#ffffff',
|
|
33
|
-
image: '#ffffff',
|
|
34
|
-
},
|
|
35
|
-
divider: '#00000015',
|
|
36
|
-
success: {
|
|
37
|
-
main: '#01D26A',
|
|
38
|
-
},
|
|
39
|
-
action: {
|
|
40
|
-
hoverOpacity: 0.16,
|
|
41
|
-
},
|
|
42
|
-
text: {
|
|
43
|
-
primary: '#000000',
|
|
44
|
-
secondary: 'hsl(229, 16%, 71%)',
|
|
45
|
-
disabled: '#00000030',
|
|
46
|
-
},
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const darkPalette: PaletteOptions = {
|
|
50
|
-
mode: 'dark',
|
|
51
|
-
primary: {
|
|
52
|
-
main,
|
|
53
|
-
contrastText: '#ffffff',
|
|
54
|
-
dark,
|
|
55
|
-
},
|
|
56
|
-
secondary: {
|
|
57
|
-
main: '#62C7B0',
|
|
58
|
-
light: '#62C7B0',
|
|
59
|
-
contrastText: '#ffffff',
|
|
60
|
-
},
|
|
61
|
-
background: {
|
|
62
|
-
default: '#001727',
|
|
63
|
-
paper: lighten('#001727', 0.03),
|
|
64
|
-
image: '#F8F8F8',
|
|
65
|
-
},
|
|
66
|
-
divider: '#ffffff30',
|
|
67
|
-
success: {
|
|
68
|
-
main: '#01D26A',
|
|
69
|
-
},
|
|
70
|
-
action: {
|
|
71
|
-
hoverOpacity: 0.16,
|
|
72
|
-
},
|
|
73
|
-
text: {
|
|
74
|
-
primary: '#ffffff',
|
|
75
|
-
secondary: '#ffffff80',
|
|
76
|
-
disabled: '#ffffff30',
|
|
77
|
-
},
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const fontSize = (from: number, to: number) =>
|
|
81
|
-
breakpointVal('fontSize', from, to, themeBaseDefaults.breakpoints.values)
|
|
82
|
-
|
|
83
|
-
// Create a theme instance.
|
|
84
|
-
const createThemeWithPalette = (palette: PaletteOptions) =>
|
|
85
|
-
createTheme({
|
|
86
|
-
palette,
|
|
87
|
-
...themeBaseDefaults,
|
|
88
|
-
shape: { borderRadius: 4 },
|
|
89
|
-
typography: {
|
|
90
|
-
fontFamily:
|
|
91
|
-
'-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji',
|
|
92
|
-
// @see docs typography.md
|
|
93
|
-
h1: {
|
|
94
|
-
...fontSize(36, 44),
|
|
95
|
-
fontWeight: 550,
|
|
96
|
-
lineHeight: 1.22,
|
|
97
|
-
fontVariationSettings: palette.mode === 'dark' ? "'wght' 550" : "'wght' 610",
|
|
98
|
-
},
|
|
99
|
-
h2: {
|
|
100
|
-
...fontSize(24, 32),
|
|
101
|
-
fontWeight: 530,
|
|
102
|
-
lineHeight: 1.6,
|
|
103
|
-
fontVariationSettings: palette.mode === 'dark' ? "'wght' 480" : "'wght' 590",
|
|
104
|
-
},
|
|
105
|
-
h3: {
|
|
106
|
-
...fontSize(18, 22),
|
|
107
|
-
fontWeight: 500,
|
|
108
|
-
lineHeight: 1.55,
|
|
109
|
-
fontVariationSettings: palette.mode === 'dark' ? "'wght' 500" : "'wght' 560",
|
|
110
|
-
},
|
|
111
|
-
h4: {
|
|
112
|
-
...fontSize(18, 23),
|
|
113
|
-
fontWeight: 600,
|
|
114
|
-
lineHeight: 1.6,
|
|
115
|
-
fontVariationSettings: "'wght' 600",
|
|
116
|
-
},
|
|
117
|
-
h5: {
|
|
118
|
-
...fontSize(18, 21),
|
|
119
|
-
fontWeight: 480,
|
|
120
|
-
lineHeight: 1.6,
|
|
121
|
-
fontVariationSettings: "'wght' 510",
|
|
122
|
-
},
|
|
123
|
-
h6: {
|
|
124
|
-
...fontSize(16, 19),
|
|
125
|
-
fontWeight: 460,
|
|
126
|
-
lineHeight: 1.8,
|
|
127
|
-
fontVariationSettings: "'wght' 460",
|
|
128
|
-
},
|
|
129
|
-
subtitle1: {
|
|
130
|
-
...fontSize(16, 19),
|
|
131
|
-
fontWeight: 450,
|
|
132
|
-
fontVariationSettings: "'wght' 460",
|
|
133
|
-
lineHeight: 1.7,
|
|
134
|
-
},
|
|
135
|
-
fontWeightBold: 600,
|
|
136
|
-
body1: {
|
|
137
|
-
...fontSize(15, 18),
|
|
138
|
-
fontWeight: 370,
|
|
139
|
-
fontVariationSettings: palette.mode === 'dark' ? "'wght' 450" : "'wght' 370",
|
|
140
|
-
lineHeight: 1.7,
|
|
141
|
-
},
|
|
142
|
-
subtitle2: {
|
|
143
|
-
...fontSize(14, 16),
|
|
144
|
-
fontWeight: 500,
|
|
145
|
-
fontVariationSettings: "'wght' 450",
|
|
146
|
-
lineHeight: 1.7,
|
|
147
|
-
},
|
|
148
|
-
body2: {
|
|
149
|
-
...fontSize(13, 15),
|
|
150
|
-
lineHeight: 1.7,
|
|
151
|
-
},
|
|
152
|
-
caption: {
|
|
153
|
-
// https://web.dev/font-size/#how-the-lighthouse-font-size-audit-fails
|
|
154
|
-
...fontSize(12, 13),
|
|
155
|
-
},
|
|
156
|
-
button: {},
|
|
157
|
-
overline: {
|
|
158
|
-
// https://web.dev/font-size/#how-the-lighthouse-font-size-audit-fails
|
|
159
|
-
...fontSize(12, 14),
|
|
160
|
-
fontWeight: 500,
|
|
161
|
-
letterSpacing: 1,
|
|
162
|
-
lineHeight: 1.2,
|
|
163
|
-
textTransform: 'uppercase',
|
|
164
|
-
},
|
|
165
|
-
},
|
|
166
|
-
spacings: {
|
|
167
|
-
xxs: responsiveVal(10, 16),
|
|
168
|
-
xs: responsiveVal(12, 20),
|
|
169
|
-
sm: responsiveVal(14, 30),
|
|
170
|
-
md: responsiveVal(16, 50),
|
|
171
|
-
lg: responsiveVal(24, 80),
|
|
172
|
-
xl: responsiveVal(40, 100),
|
|
173
|
-
xxl: responsiveVal(80, 160),
|
|
174
|
-
},
|
|
175
|
-
page: {
|
|
176
|
-
horizontal: responsiveVal(10, 30),
|
|
177
|
-
vertical: responsiveVal(10, 30),
|
|
178
|
-
},
|
|
179
|
-
appShell: {
|
|
180
|
-
headerHeightSm: '46px',
|
|
181
|
-
headerHeightMd: '80px',
|
|
182
|
-
appBarHeightMd: '80px',
|
|
183
|
-
appBarInnerHeightMd: '46px',
|
|
184
|
-
},
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
// todo: move most of the styles to the graphcommerce library while still allowing for extensibility.
|
|
188
|
-
const createOverrides = (theme: Theme): Components => ({
|
|
189
|
-
MuiCssBaseline: {
|
|
190
|
-
styleOverrides: {
|
|
191
|
-
body: {
|
|
192
|
-
overflowY: 'scroll',
|
|
193
|
-
},
|
|
194
|
-
'::selection': { background: alpha(theme.palette.primary.main, 0.6) },
|
|
195
|
-
'::-moz-selection': { background: alpha(theme.palette.primary.main, 0.6) },
|
|
196
|
-
'#__next': {
|
|
197
|
-
position: 'relative',
|
|
198
|
-
},
|
|
199
|
-
img: {
|
|
200
|
-
filter: 'brightness(1.03)',
|
|
201
|
-
willChange: 'filter',
|
|
202
|
-
},
|
|
203
|
-
},
|
|
204
|
-
},
|
|
205
|
-
|
|
206
|
-
MuiContainer: {
|
|
207
|
-
variants: [
|
|
208
|
-
{
|
|
209
|
-
props: { disableGutters: false },
|
|
210
|
-
style: {
|
|
211
|
-
paddingLeft: theme.page.horizontal,
|
|
212
|
-
paddingRight: theme.page.horizontal,
|
|
213
|
-
[theme.breakpoints.up('sm')]: {
|
|
214
|
-
paddingLeft: theme.page.horizontal,
|
|
215
|
-
paddingRight: theme.page.horizontal,
|
|
216
|
-
},
|
|
217
|
-
},
|
|
218
|
-
},
|
|
219
|
-
],
|
|
220
|
-
},
|
|
221
|
-
|
|
222
|
-
MuiInputBase: {
|
|
223
|
-
styleOverrides: {
|
|
224
|
-
root: {
|
|
225
|
-
fontSize: '16px', // https://css-tricks.com/16px-or-larger-text-prevents-ios-form-zoom/
|
|
226
|
-
},
|
|
227
|
-
},
|
|
228
|
-
},
|
|
229
|
-
|
|
230
|
-
MuiButton: {
|
|
231
|
-
defaultProps: { color: 'inherit' },
|
|
232
|
-
variants: [
|
|
233
|
-
...MuiButtonResponsive,
|
|
234
|
-
...MuiButtonPill,
|
|
235
|
-
{
|
|
236
|
-
props: { variant: 'contained', color: 'inherit' },
|
|
237
|
-
style: { backgroundColor: theme.palette.background.paper },
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
props: { variant: 'outlined' },
|
|
241
|
-
style: {
|
|
242
|
-
borderRadius: responsiveVal(theme.shape.borderRadius * 2, theme.shape.borderRadius * 3),
|
|
243
|
-
},
|
|
244
|
-
},
|
|
245
|
-
{
|
|
246
|
-
props: { variant: 'text' },
|
|
247
|
-
style: { borderRadius: '99em' },
|
|
248
|
-
},
|
|
249
|
-
],
|
|
250
|
-
},
|
|
251
|
-
|
|
252
|
-
MuiFab: {
|
|
253
|
-
styleOverrides: {
|
|
254
|
-
root: {
|
|
255
|
-
backgroundColor: theme.palette.background.paper,
|
|
256
|
-
'&:hover': {
|
|
257
|
-
backgroundColor: theme.palette.background.paper,
|
|
258
|
-
},
|
|
259
|
-
color: theme.palette.text.primary,
|
|
260
|
-
},
|
|
261
|
-
colorInherit: {
|
|
262
|
-
backgroundColor: 'inherit',
|
|
263
|
-
'&:hover, &:focus': {
|
|
264
|
-
backgroundColor: 'inherit',
|
|
265
|
-
},
|
|
266
|
-
boxShadow: 'none',
|
|
267
|
-
},
|
|
268
|
-
primary: {
|
|
269
|
-
color: theme.palette.text.primary,
|
|
270
|
-
},
|
|
271
|
-
secondary: {
|
|
272
|
-
color: theme.palette.text.primary,
|
|
273
|
-
},
|
|
274
|
-
extended: {
|
|
275
|
-
fontWeight: 400,
|
|
276
|
-
textTransform: 'none',
|
|
277
|
-
},
|
|
278
|
-
},
|
|
279
|
-
variants: [...MuiFabSizes],
|
|
280
|
-
},
|
|
281
|
-
|
|
282
|
-
MuiTextField: {
|
|
283
|
-
styleOverrides: {
|
|
284
|
-
root: {
|
|
285
|
-
'& label.Mui-focused': {
|
|
286
|
-
color: theme.palette.secondary.main,
|
|
287
|
-
},
|
|
288
|
-
'& .MuiOutlinedInput-root': {
|
|
289
|
-
borderRadius: responsiveVal(theme.shape.borderRadius * 1.5, theme.shape.borderRadius * 2),
|
|
290
|
-
'& fieldset': {
|
|
291
|
-
borderColor: theme.palette.divider,
|
|
292
|
-
},
|
|
293
|
-
'&.Mui-focused fieldset': {
|
|
294
|
-
borderColor: theme.palette.divider,
|
|
295
|
-
borderWidth: 1,
|
|
296
|
-
},
|
|
297
|
-
},
|
|
298
|
-
},
|
|
299
|
-
},
|
|
300
|
-
},
|
|
301
|
-
|
|
302
|
-
MuiListItemIcon: {
|
|
303
|
-
styleOverrides: {
|
|
304
|
-
root: {
|
|
305
|
-
color: theme.palette.text.primary,
|
|
306
|
-
},
|
|
307
|
-
},
|
|
308
|
-
},
|
|
309
|
-
|
|
310
|
-
MuiChip: {
|
|
311
|
-
styleOverrides: {
|
|
312
|
-
root: {
|
|
313
|
-
boxShadow: 'unset !important',
|
|
314
|
-
borderRadius: '99em',
|
|
315
|
-
height: responsiveVal(32, 40),
|
|
316
|
-
paddingLeft: responsiveVal(4, 8),
|
|
317
|
-
paddingRight: responsiveVal(4, 8),
|
|
318
|
-
...theme.typography.body2,
|
|
319
|
-
},
|
|
320
|
-
sizeSmall: {
|
|
321
|
-
height: responsiveVal(26, 30),
|
|
322
|
-
paddingLeft: responsiveVal(3, 6),
|
|
323
|
-
paddingRight: responsiveVal(3, 6),
|
|
324
|
-
...theme.typography.caption,
|
|
325
|
-
},
|
|
326
|
-
outlined: {
|
|
327
|
-
borderColor: theme.palette.divider,
|
|
328
|
-
},
|
|
329
|
-
label: {
|
|
330
|
-
paddingLeft: responsiveVal(6, 10),
|
|
331
|
-
paddingRight: responsiveVal(6, 10),
|
|
332
|
-
},
|
|
333
|
-
labelSmall: {
|
|
334
|
-
paddingLeft: responsiveVal(6, 8),
|
|
335
|
-
paddingRight: responsiveVal(6, 8),
|
|
336
|
-
},
|
|
337
|
-
deleteIcon: {
|
|
338
|
-
color: theme.palette.text.primary,
|
|
339
|
-
// display: 'flex',
|
|
340
|
-
},
|
|
341
|
-
deleteIconOutlinedColorPrimary: {
|
|
342
|
-
// color: theme.palette.primary.main,
|
|
343
|
-
},
|
|
344
|
-
},
|
|
345
|
-
},
|
|
346
|
-
|
|
347
|
-
MuiCheckbox: {
|
|
348
|
-
styleOverrides: {
|
|
349
|
-
colorPrimary: {
|
|
350
|
-
color: theme.palette.text.disabled,
|
|
351
|
-
'&.Mui-checked': {
|
|
352
|
-
color: theme.palette.primary.main,
|
|
353
|
-
},
|
|
354
|
-
},
|
|
355
|
-
colorSecondary: {
|
|
356
|
-
color: theme.palette.text.disabled,
|
|
357
|
-
'&.Mui-checked': {
|
|
358
|
-
color: theme.palette.secondary.main,
|
|
359
|
-
},
|
|
360
|
-
},
|
|
361
|
-
},
|
|
362
|
-
},
|
|
363
|
-
|
|
364
|
-
MuiSwitch: {
|
|
365
|
-
styleOverrides: {
|
|
366
|
-
track: {
|
|
367
|
-
'.Mui-colorPrimary + &': {
|
|
368
|
-
backgroundColor: theme.palette.primary,
|
|
369
|
-
borderRadius: '30px',
|
|
370
|
-
},
|
|
371
|
-
'.Mui-checked.Mui-colorPrimary + &': {
|
|
372
|
-
opacity: 1,
|
|
373
|
-
backgroundColor: theme.palette.primary,
|
|
374
|
-
borderRadius: '30px',
|
|
375
|
-
},
|
|
376
|
-
},
|
|
377
|
-
thumb: {
|
|
378
|
-
backgroundColor: '#fff',
|
|
379
|
-
},
|
|
380
|
-
},
|
|
381
|
-
},
|
|
382
|
-
|
|
383
|
-
MuiSnackbar: { variants: MuiSnackbar },
|
|
384
|
-
|
|
385
|
-
MuiAvatar: {
|
|
386
|
-
styleOverrides: {
|
|
387
|
-
colorDefault: {
|
|
388
|
-
backgroundColor: theme.palette.text.disabled,
|
|
389
|
-
},
|
|
390
|
-
},
|
|
391
|
-
},
|
|
392
|
-
|
|
393
|
-
MuiSlider: {
|
|
394
|
-
styleOverrides: {
|
|
395
|
-
rail: {
|
|
396
|
-
color: theme.palette.text.disabled,
|
|
397
|
-
},
|
|
398
|
-
thumb: {
|
|
399
|
-
background: theme.palette.background.default,
|
|
400
|
-
boxShadow: theme.shadows[6],
|
|
401
|
-
},
|
|
402
|
-
},
|
|
403
|
-
},
|
|
404
|
-
})
|
|
405
|
-
|
|
406
|
-
export const lightTheme = createThemeWithPalette(lightPalette)
|
|
407
|
-
lightTheme.components = createOverrides(lightTheme)
|
|
408
|
-
|
|
409
|
-
export const darkTheme = createThemeWithPalette(darkPalette)
|
|
410
|
-
darkTheme.components = createOverrides(darkTheme)
|
package/lib/DocumentIndexer.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/* eslint-disable class-methods-use-this */
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import { remark } from 'remark'
|
|
4
|
-
import remarkGfm from 'remark-gfm'
|
|
5
|
-
import strip from 'strip-markdown'
|
|
6
|
-
import { toVFile as vfile } from 'to-vfile'
|
|
7
|
-
import { matter } from 'vfile-matter'
|
|
8
|
-
import { FileNode, findByUrl, getDirectoryPaths, getDirectoryTree } from './files'
|
|
9
|
-
import { indexName } from './instantSearch'
|
|
10
|
-
import { BaseDocument, SearchIndexer } from './typesense/SearchIndexer'
|
|
11
|
-
|
|
12
|
-
export type DocumentationDocument = BaseDocument & {
|
|
13
|
-
url: string
|
|
14
|
-
content: string
|
|
15
|
-
name: string
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export class DocumentIndexer extends SearchIndexer<DocumentationDocument> {
|
|
19
|
-
#root: string
|
|
20
|
-
|
|
21
|
-
constructor(root: string) {
|
|
22
|
-
super({
|
|
23
|
-
name: indexName,
|
|
24
|
-
fields: {
|
|
25
|
-
id: { type: 'string' },
|
|
26
|
-
name: { type: 'string' },
|
|
27
|
-
url: { type: 'string' },
|
|
28
|
-
content: { type: 'string' },
|
|
29
|
-
},
|
|
30
|
-
})
|
|
31
|
-
this.#root = root
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// load a single document
|
|
35
|
-
async #loadDocument(node?: FileNode | false): Promise<DocumentationDocument> {
|
|
36
|
-
if (!node) throw Error('Node not found')
|
|
37
|
-
|
|
38
|
-
const file = path.join(process.cwd(), this.#root, node.path)
|
|
39
|
-
const res = matter(await vfile.read(file), { strip: true })
|
|
40
|
-
const content = (await remark().use(strip).process(res)).value.toString()
|
|
41
|
-
|
|
42
|
-
if (!content) throw Error('Can not load file')
|
|
43
|
-
|
|
44
|
-
const { name, url } = node
|
|
45
|
-
return { id: node.path, content, url, name: node.matter.menu ?? name }
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async *all() {
|
|
49
|
-
const paths = await getDirectoryPaths(this.#root)
|
|
50
|
-
const menuData = await getDirectoryTree(this.#root)
|
|
51
|
-
if (!menuData) return false
|
|
52
|
-
|
|
53
|
-
for (const p of paths) {
|
|
54
|
-
yield this.#loadDocument(findByUrl(p.split('/'), menuData))
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return true
|
|
58
|
-
}
|
|
59
|
-
}
|
package/lib/files.ts
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import { toVFile as vfile } from 'to-vfile'
|
|
4
|
-
import { matter } from 'vfile-matter'
|
|
5
|
-
|
|
6
|
-
export type MatterFields = {
|
|
7
|
-
menu?: string
|
|
8
|
-
order?: string
|
|
9
|
-
metaTitle?: string
|
|
10
|
-
metaDescription?: string
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
type BaseFields = {
|
|
14
|
-
type: 'folder' | 'file'
|
|
15
|
-
path: string
|
|
16
|
-
name: string
|
|
17
|
-
childNodes?: FileOrFolderNode[]
|
|
18
|
-
matter?: MatterFields
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type FolderNode = BaseFields & { type?: 'folder' }
|
|
22
|
-
export type FileNode = BaseFields & { type?: 'file'; url: string; matter: MatterFields }
|
|
23
|
-
|
|
24
|
-
export type FileOrFolderNode = FolderNode | FileNode
|
|
25
|
-
|
|
26
|
-
function toUrl(p: string) {
|
|
27
|
-
let url = p.replace('.mdx', '')
|
|
28
|
-
url = url.replace('.md', '')
|
|
29
|
-
url = url.endsWith('/') ? url.slice(0, -1) : url
|
|
30
|
-
return url
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async function dirTree(dir: string, root: string): Promise<FileOrFolderNode> {
|
|
34
|
-
const stats = await fs.promises.lstat(dir)
|
|
35
|
-
|
|
36
|
-
let name = path.basename(dir)
|
|
37
|
-
name = name.replace('.mdx', '')
|
|
38
|
-
name = name.replace('.md', '')
|
|
39
|
-
name = name.replace(/-/g, ' ').replace(/^./, (x) => x.toUpperCase())
|
|
40
|
-
|
|
41
|
-
const filePath = path.relative(root, dir)
|
|
42
|
-
|
|
43
|
-
const info: Partial<FileOrFolderNode> = { path: filePath, name }
|
|
44
|
-
|
|
45
|
-
if (stats.isDirectory()) {
|
|
46
|
-
info.type = 'folder'
|
|
47
|
-
info.childNodes = await Promise.all(
|
|
48
|
-
(await fs.promises.readdir(dir)).map((child) => dirTree(`${dir}/${child}`, root)),
|
|
49
|
-
)
|
|
50
|
-
} else {
|
|
51
|
-
info.type = 'file'
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (info.type === 'file') {
|
|
55
|
-
info.url = toUrl(path.relative(root, dir))
|
|
56
|
-
info.matter = matter(await vfile.read(dir)).data.matter as Record<string, string>
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return info as FileOrFolderNode
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Replace the path of the parent with the path of the child having index.mdx as name and remove from children.
|
|
63
|
-
// Do this recursively for each child.
|
|
64
|
-
// Remove type from tree
|
|
65
|
-
function hoistIndex(tree: FileOrFolderNode): FileOrFolderNode {
|
|
66
|
-
let newTree: FileOrFolderNode = tree
|
|
67
|
-
|
|
68
|
-
if (newTree.type === 'folder') {
|
|
69
|
-
const index = newTree.childNodes?.find(
|
|
70
|
-
(child) =>
|
|
71
|
-
child.path.endsWith('readme.mdx') ||
|
|
72
|
-
(child.path.endsWith('readme.md') && child.type === 'file'),
|
|
73
|
-
) as FileNode | undefined
|
|
74
|
-
|
|
75
|
-
if (index) {
|
|
76
|
-
newTree = { ...index, name: tree.name, url: index.url.slice(0, -7) }
|
|
77
|
-
newTree.childNodes = tree.childNodes?.filter((child) => child !== index)
|
|
78
|
-
|
|
79
|
-
const order = index.matter?.order?.split(',').map((x) => x.trim())
|
|
80
|
-
if (order) {
|
|
81
|
-
newTree.childNodes = newTree.childNodes?.sort((a, b) => {
|
|
82
|
-
const aPath = toUrl(a.path.split('/').pop() as string)
|
|
83
|
-
const bPath = toUrl(b.path.split('/').pop() as string)
|
|
84
|
-
return order.indexOf(aPath) === -1 ? 1 : order.indexOf(aPath) - order.indexOf(bPath)
|
|
85
|
-
})
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
newTree.childNodes = newTree.childNodes?.map((child) => hoistIndex(child))
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return newTree
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export async function getDirectoryTree(dir: string): Promise<false | FileNode> {
|
|
95
|
-
const absDir = path.join(process.cwd(), dir)
|
|
96
|
-
|
|
97
|
-
const tree = await dirTree(absDir, absDir)
|
|
98
|
-
|
|
99
|
-
return hoistIndex(tree) as FileNode
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export async function getDirectoryPaths(dir: string) {
|
|
103
|
-
const menuData = await getDirectoryTree(dir)
|
|
104
|
-
|
|
105
|
-
const paths: string[] = []
|
|
106
|
-
const addPathsFromTree = (tree: FileOrFolderNode) => {
|
|
107
|
-
if (tree.type === 'file') paths.push(tree.url)
|
|
108
|
-
|
|
109
|
-
if (tree.childNodes?.length) {
|
|
110
|
-
tree.childNodes.forEach((child) => addPathsFromTree(child))
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
if (menuData) addPathsFromTree(menuData)
|
|
114
|
-
|
|
115
|
-
return paths
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Recursively traverse the tree and return the aggregated path of of each node.
|
|
120
|
-
*
|
|
121
|
-
* Each URL segment should reference a path (except for the readme.md/readme.mdx file)
|
|
122
|
-
*/
|
|
123
|
-
export function urlToPath(url: string[], node: FileOrFolderNode): string | false {
|
|
124
|
-
if (node.childNodes?.length) {
|
|
125
|
-
const child = node.childNodes?.reduce<string | false>((prev, curr) => {
|
|
126
|
-
if (prev) return prev
|
|
127
|
-
const childPath = urlToPath(url, curr)
|
|
128
|
-
return childPath ?? prev
|
|
129
|
-
}, false)
|
|
130
|
-
|
|
131
|
-
if (child) return child
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (node.type === 'file' && node.url === url.join('/')) return node.path
|
|
135
|
-
|
|
136
|
-
return false
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/** Get the contens of the requested file. */
|
|
140
|
-
export function getFileContents(dir: string, filePath: string) {
|
|
141
|
-
const absDir = path.join(process.cwd(), dir, filePath)
|
|
142
|
-
try {
|
|
143
|
-
return fs.promises.readFile(absDir, 'utf8')
|
|
144
|
-
} catch (e) {
|
|
145
|
-
return false
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Recursively traverse the tree and return the aggregated path of of each node.
|
|
151
|
-
*
|
|
152
|
-
* Each URL segment should reference a path (except for the readme.md/readme.mdx file)
|
|
153
|
-
*/
|
|
154
|
-
export function findByUrl(url: string[], node: FileOrFolderNode): FileNode | false {
|
|
155
|
-
if (node.childNodes?.length) {
|
|
156
|
-
const child = node.childNodes?.reduce<FileNode | false>((prev, curr) => {
|
|
157
|
-
if (prev) return prev
|
|
158
|
-
const childPath = findByUrl(url, curr)
|
|
159
|
-
return childPath ?? prev
|
|
160
|
-
}, false)
|
|
161
|
-
|
|
162
|
-
if (child) return child
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (node.type === 'file' && node.url === url.join('/')) return node
|
|
166
|
-
|
|
167
|
-
return false
|
|
168
|
-
}
|
package/lib/instantSearch.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { HitsRenderState } from 'instantsearch.js/es/connectors/hits/connectHits'
|
|
2
|
-
import { useHits as useHitsBase } from 'react-instantsearch-hooks'
|
|
3
|
-
import { SetReturnType } from 'type-fest'
|
|
4
|
-
import type { DocumentationDocument } from './DocumentIndexer'
|
|
5
|
-
import { createInstantSearchProps } from './typesense/createInstantSearchProps'
|
|
6
|
-
|
|
7
|
-
export const indexName = 'documents'
|
|
8
|
-
|
|
9
|
-
export const instantSearchProps = createInstantSearchProps<DocumentationDocument>(indexName, {
|
|
10
|
-
query_by: {
|
|
11
|
-
name: 2,
|
|
12
|
-
content: 1,
|
|
13
|
-
},
|
|
14
|
-
numTypos: '1',
|
|
15
|
-
typoTokensThreshold: 1,
|
|
16
|
-
highlight_fields: 'content',
|
|
17
|
-
highlight_full_fields: 'name',
|
|
18
|
-
include_fields: 'name,url',
|
|
19
|
-
// highlight_affix_num_tokens: ,
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
const useHits: SetReturnType<typeof useHitsBase, HitsRenderState<DocumentationDocument>> = (
|
|
23
|
-
...params
|
|
24
|
-
) => useHitsBase(...params) as HitsRenderState<DocumentationDocument>
|
|
25
|
-
|
|
26
|
-
export { useHits }
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { Client } from 'typesense/lib/Typesense'
|
|
2
|
-
import { ConfigurationOptions } from 'typesense/lib/Typesense/Configuration'
|
|
3
|
-
import { ObjectNotFound } from 'typesense/lib/Typesense/Errors'
|
|
4
|
-
import { BaseDocument, SearchIndexer } from './SearchIndexer'
|
|
5
|
-
import { batchIterable } from './batchInterable'
|
|
6
|
-
|
|
7
|
-
export class IndexerHandler {
|
|
8
|
-
client: Client
|
|
9
|
-
|
|
10
|
-
constructor(
|
|
11
|
-
clientOptions: ConfigurationOptions,
|
|
12
|
-
public indexers: SearchIndexer<BaseDocument>[],
|
|
13
|
-
private batchSize: number = 1000,
|
|
14
|
-
) {
|
|
15
|
-
this.client = new Client(clientOptions)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
async all() {
|
|
19
|
-
let count = 0
|
|
20
|
-
for await (const indexer of this.indexers) {
|
|
21
|
-
const resCount = await this.#reindex(indexer)
|
|
22
|
-
count += resCount
|
|
23
|
-
}
|
|
24
|
-
return count
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** @throws {TypesenseError} */
|
|
28
|
-
async #reindex(indexer: SearchIndexer<BaseDocument>) {
|
|
29
|
-
const { name } = indexer.schema
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
await this.client.collections(name).retrieve()
|
|
33
|
-
await this.client.collections(name).delete()
|
|
34
|
-
} catch (e) {
|
|
35
|
-
if (!(e instanceof ObjectNotFound)) throw e
|
|
36
|
-
}
|
|
37
|
-
await this.client.collections().create(indexer.schema)
|
|
38
|
-
|
|
39
|
-
let count = 0
|
|
40
|
-
for await (const documents of batchIterable(indexer.all(), this.batchSize)) {
|
|
41
|
-
const result = await this.client.collections(name).documents().import(documents)
|
|
42
|
-
count += result.length
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return count
|
|
46
|
-
}
|
|
47
|
-
}
|