@brillout/docpress 0.9.7 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/Layout.tsx +102 -40
  2. package/{navigation → MenuModal}/Collapsible.css +7 -0
  3. package/MenuModal/NavigationWithColumnLayout.css +11 -0
  4. package/MenuModal/NavigationWithColumnLayout.tsx +253 -0
  5. package/MenuModal/toggleMenuModal.ts +132 -0
  6. package/MenuModal.tsx +68 -79
  7. package/{navigation/Navigation.css → NavItemComponent.css} +1 -23
  8. package/NavItemComponent.tsx +149 -0
  9. package/components/Note.css +0 -1
  10. package/config/resolveHeadingsData.ts +1 -1
  11. package/css/code/diff.css +10 -5
  12. package/css/code.css +1 -1
  13. package/css/colorize-on-hover.css +6 -7
  14. package/css/heading.css +9 -3
  15. package/css/index.css +1 -0
  16. package/dist/NavItemComponent.d.ts +39 -0
  17. package/dist/NavItemComponent.js +109 -0
  18. package/dist/config/resolveHeadingsData.d.ts +1 -1
  19. package/dist/config/resolvePageContext.d.ts +2 -2
  20. package/dist/renderer/determineNavItemsColumnLayout.d.ts +1 -1
  21. package/dist/renderer/usePageContext.js +4 -3
  22. package/docsearch/SearchLink.tsx +7 -3
  23. package/icons/books.svg +46 -0
  24. package/icons/gear.svg +35 -0
  25. package/icons/index.ts +5 -0
  26. package/icons/magnifying-glass.svg +31 -0
  27. package/icons/seedling.svg +24 -0
  28. package/index.ts +2 -0
  29. package/initKeyBindings.ts +1 -1
  30. package/package.json +1 -1
  31. package/renderer/determineNavItemsColumnLayout.ts +1 -1
  32. package/renderer/initOnNavigation.ts +1 -1
  33. package/renderer/onRenderClient.tsx +1 -1
  34. package/renderer/usePageContext.tsx +4 -3
  35. package/utils/css.ts +0 -6
  36. package/dist/Layout.d.ts +0 -15
  37. package/dist/Layout.js +0 -321
  38. package/dist/MenuModal.d.ts +0 -13
  39. package/dist/MenuModal.js +0 -124
  40. package/dist/NavSecondaryContent.d.ts +0 -6
  41. package/dist/NavSecondaryContent.js +0 -57
  42. package/dist/autoScrollNav.d.ts +0 -3
  43. package/dist/autoScrollNav.js +0 -35
  44. package/dist/components/EditPageNote.d.ts +0 -7
  45. package/dist/components/EditPageNote.js +0 -11
  46. package/dist/docsearch/SearchLink.d.ts +0 -4
  47. package/dist/docsearch/SearchLink.js +0 -25
  48. package/dist/docsearch/toggleDocsearchModal.d.ts +0 -4
  49. package/dist/docsearch/toggleDocsearchModal.js +0 -26
  50. package/dist/navigation/Collapsible.d.ts +0 -10
  51. package/dist/navigation/Collapsible.js +0 -35
  52. package/dist/navigation/Navigation.d.ts +0 -21
  53. package/dist/navigation/Navigation.js +0 -255
  54. package/dist/utils/PassTrough.d.ts +0 -3
  55. package/dist/utils/PassTrough.js +0 -6
  56. package/dist/utils/Style.d.ts +0 -5
  57. package/dist/utils/Style.js +0 -6
  58. package/dist/utils/css.d.ts +0 -1
  59. package/dist/utils/css.js +0 -27
  60. package/dist/utils/getViewportWidth.d.ts +0 -1
  61. package/dist/utils/getViewportWidth.js +0 -4
  62. package/dist/utils/throttle.d.ts +0 -1
  63. package/dist/utils/throttle.js +0 -14
  64. package/navigation/Navigation.tsx +0 -382
  65. /package/{navigation → MenuModal}/Collapsible.tsx +0 -0
@@ -1,382 +0,0 @@
1
- // TODO/refactor: rename file and/or component
2
- export { NavigationContent }
3
- // TODO/refactor: do this only on the server side?
4
- export type { NavItem }
5
-
6
- import React, { useEffect, useState } from 'react'
7
- import { assert, assertWarning, jsxToTextContent } from '../utils/server'
8
- import './Navigation.css'
9
- import { parseTitle } from '../parseTitle'
10
- import { usePageContext } from '../renderer/usePageContext'
11
- import '@docsearch/css'
12
- import '../global.d.ts'
13
- import { getViewportWidth } from '../utils/getViewportWidth'
14
- import { navLeftWidthMax, navLeftWidthMin } from '../Layout'
15
- import { throttle } from '../utils/throttle'
16
- import { Collapsible } from './Collapsible'
17
-
18
- type NavItem = {
19
- level: number
20
- url?: string | null
21
- color?: string
22
- title: string
23
- titleInNav: string
24
- menuModalFullWidth?: true
25
- isColumnEntry?: ColumnMap
26
- }
27
- function NavigationContent(props: {
28
- navItems: NavItem[]
29
- showOnlyRelevant?: true
30
- columnLayout?: true
31
- }) {
32
- const pageContext = usePageContext()
33
- const navItemsWithComputed = getNavItemsWithComputed(props.navItems, pageContext.urlPathname)
34
-
35
- let navContent: React.ReactNode
36
- if (!props.columnLayout) {
37
- let navItemsRelevant = navItemsWithComputed
38
- if (props.showOnlyRelevant) navItemsRelevant = navItemsRelevant.filter((navItemGroup) => navItemGroup.isRelevant)
39
- navContent = navItemsRelevant.map((navItem, i) => <NavItemComponent navItem={navItem} key={i} />)
40
- } else {
41
- assert(!props.showOnlyRelevant)
42
- navContent = <NavigationWithColumnLayout navItemsWithComputed={navItemsWithComputed} />
43
- }
44
-
45
- return (
46
- <div className="navigation-content" style={{ marginTop: 10 }}>
47
- {navContent}
48
- </div>
49
- )
50
- }
51
-
52
- function NavigationWithColumnLayout(props: { navItemsWithComputed: NavItemComputed[] }) {
53
- let [viewportWidth, setViewportWidth] = useState<number | undefined>()
54
- const updateviewportwidth = () => setViewportWidth(getViewportWidth())
55
- useEffect(() => {
56
- updateviewportwidth()
57
- window.addEventListener('resize', throttle(updateviewportwidth, 300), { passive: true })
58
- })
59
- const navItemsByColumnLayouts = getNavItemsByColumnLayouts(props.navItemsWithComputed, viewportWidth)
60
- return (
61
- <>
62
- {navItemsByColumnLayouts.map((columnLayout, i) => (
63
- <div key={i}>
64
- {columnLayout.isFullWidthCategory ? (
65
- <div style={{ marginTop: 0 }}>
66
- <ColumnsWrapper numberOfColumns={columnLayout.columns.length}>
67
- <Collapsible
68
- head={(onClick) => <NavItemComponent navItem={columnLayout.navItemLevel1} onClick={onClick} />}
69
- disabled={columnLayout.columns.length > 1}
70
- collapsedInit={!columnLayout.navItemLevel1.isRelevant}
71
- marginBottomOnExpand={10}
72
- >
73
- <ColumnsLayout className="collapsible">
74
- {columnLayout.columns.map((column, j) => (
75
- <Column key={j}>
76
- {column.navItems.map((navItem, k) => (
77
- <NavItemComponent key={k} navItem={navItem} />
78
- ))}
79
- </Column>
80
- ))}
81
- <CategoryBorder navItemLevel1={columnLayout.navItemLevel1} />
82
- </ColumnsLayout>
83
- </Collapsible>
84
- </ColumnsWrapper>
85
- </div>
86
- ) : (
87
- <ColumnsWrapper numberOfColumns={columnLayout.columns.length}>
88
- <ColumnsLayout>
89
- {columnLayout.columns.map((column, j) => (
90
- <Column key={j}>
91
- {column.categories.map((category, k) => (
92
- <div key={k} style={{ marginBottom: 0 }}>
93
- <Collapsible
94
- head={(onClick) => <NavItemComponent navItem={category.navItemLevel1} onClick={onClick} />}
95
- disabled={columnLayout.columns.length > 1}
96
- collapsedInit={!category.navItemLevel1.isRelevant}
97
- marginBottomOnExpand={40}
98
- >
99
- {category.navItems.map((navItem, l) => (
100
- <NavItemComponent key={l} navItem={navItem} />
101
- ))}
102
- <CategoryBorder navItemLevel1={category.navItemLevel1} />
103
- </Collapsible>
104
- </div>
105
- ))}
106
- </Column>
107
- ))}
108
- </ColumnsLayout>
109
- </ColumnsWrapper>
110
- )}
111
- </div>
112
- ))}
113
- </>
114
- )
115
- }
116
- function Column({ children }: { children: React.ReactNode }) {
117
- return (
118
- <div
119
- style={{
120
- flexGrow: 1,
121
- maxWidth: navLeftWidthMax,
122
- display: 'flex',
123
- flexDirection: 'column',
124
- }}
125
- >
126
- {children}
127
- </div>
128
- )
129
- }
130
- function ColumnsWrapper({ children, numberOfColumns }: { children: React.ReactNode; numberOfColumns: number }) {
131
- return (
132
- <div
133
- style={{
134
- width: numberOfColumns * (navLeftWidthMax + 20),
135
- maxWidth: '100%',
136
- margin: 'auto',
137
- }}
138
- >
139
- {children}
140
- </div>
141
- )
142
- }
143
- function ColumnsLayout({ children, className }: { children: React.ReactNode; className?: string }) {
144
- return (
145
- <div
146
- className={className}
147
- style={{
148
- display: 'flex',
149
- justifyContent: 'space-between',
150
- }}
151
- >
152
- {children}
153
- </div>
154
- )
155
- }
156
- function CategoryBorder({ navItemLevel1 }: { navItemLevel1: NavItemComputed }) {
157
- assert(navItemLevel1.level === 1)
158
- return <div className="category-border" style={{ background: navItemLevel1.color! }} />
159
- }
160
-
161
- type PropsNavItem = PropsAnchor & PropsSpan
162
- type PropsAnchor = React.HTMLProps<HTMLAnchorElement>
163
- type PropsSpan = React.HTMLProps<HTMLSpanElement>
164
- function NavItemComponent({
165
- navItem,
166
- onClick,
167
- }: {
168
- navItem: NavItemComputed
169
- onClick?: PropsNavItem['onClick']
170
- }) {
171
- assert([1, 2, 3, 4].includes(navItem.level), navItem)
172
-
173
- const titleJsx = parseTitle(navItem.title)
174
- const titleInNavJsx = parseTitle(navItem.titleInNav)
175
-
176
- if (navItem.level === 1 || navItem.level === 4) {
177
- assert(navItem.url === undefined)
178
- } else {
179
- const sectionTitle = jsxToTextContent(titleJsx)
180
- assertWarning(
181
- navItem.url,
182
- [
183
- `${jsxToTextContent(titleInNavJsx)} is missing a URL hash.`,
184
- `Add a URL hash with: \`## ${sectionTitle}{#some-hash}\`.`,
185
- /* TODO/eventually: not implemented yet.
186
- `Use \`<h2 id="url-hash">${sectionTitle}</h2>\` instead of \`## ${sectionTitle}\`.`,
187
- */
188
- ].join(' '),
189
- )
190
- }
191
-
192
- let children: JSX.Element = titleInNavJsx
193
- if (navItem.level === 1) {
194
- children = (
195
- <>
196
- {children}
197
- <Chevron className="collapsible-icon" height={9} />
198
- </>
199
- )
200
- }
201
-
202
- const props: PropsNavItem = {
203
- href: navItem.url ?? undefined,
204
- children,
205
- onClick,
206
- className: [
207
- 'nav-item',
208
- 'nav-item-level-' + navItem.level,
209
- navItem.url && navItem.isActive && ' is-active',
210
- navItem.isFirstOfItsKind && 'nav-item-first-of-its-kind',
211
- navItem.isLastOfItsKind && 'nav-item-last-of-its-kind',
212
- ]
213
- .filter(Boolean)
214
- .join(' '),
215
- }
216
- if (navItem.level === 1) {
217
- props.style = {
218
- ['--category-color']: navItem.color!,
219
- }
220
- }
221
-
222
- if (navItem.level === 2 || navItem.level === 3) {
223
- return <a {...props} />
224
- } else {
225
- return <span {...props} />
226
- }
227
- }
228
-
229
- type NavItemsByColumnLayout =
230
- | {
231
- columns: {
232
- categories: {
233
- navItemLevel1: NavItemComputed
234
- navItems: NavItemComputed[]
235
- }[]
236
- }[]
237
- isFullWidthCategory: false
238
- }
239
- | {
240
- navItemLevel1: NavItemComputed
241
- columns: { navItems: NavItemComputed[] }[]
242
- isFullWidthCategory: true
243
- }
244
- type NavItemsByColumnLayout2 = { columns: NavItemComputed[][][]; isFullWidthCategory: boolean }
245
- function getNavItemsByColumnLayouts(navItems: NavItemComputed[], viewportWidth: number = 0): NavItemsByColumnLayout[] {
246
- const navItemsByColumnEntries = getNavItemsByColumnEntries(navItems)
247
- const numberOfColumnsMax = Math.floor(viewportWidth / navLeftWidthMin) || 1
248
- const navItemsByColumnLayouts: NavItemsByColumnLayout[] = navItemsByColumnEntries.map(
249
- ({ columnEntries, isFullWidthCategory }) => {
250
- const numberOfColumns = Math.min(numberOfColumnsMax, columnEntries.length)
251
- if (!isFullWidthCategory) {
252
- const columns: {
253
- categories: {
254
- navItemLevel1: NavItemComputed
255
- navItems: NavItemComputed[]
256
- }[]
257
- }[] = []
258
- columnEntries.forEach((columnEntry) => {
259
- const idx = numberOfColumns === 1 ? 0 : columnEntry.columnMap[numberOfColumns]!
260
- assert(idx >= 0)
261
- columns[idx] ??= { categories: [] }
262
- const navItemLevel1 = columnEntry.navItems[0]
263
- const navItems = columnEntry.navItems.slice(1)
264
- columns[idx].categories.push({ navItemLevel1, navItems })
265
- })
266
- const navItemsByColumnLayout: NavItemsByColumnLayout = { columns, isFullWidthCategory }
267
- return navItemsByColumnLayout
268
- } else {
269
- let navItemLevel1: NavItemComputed
270
- const columns: { navItems: NavItemComputed[] }[] = []
271
- columnEntries.forEach((columnEntry, i) => {
272
- const idx = numberOfColumns === 1 ? 0 : columnEntry.columnMap[numberOfColumns]!
273
- assert(idx >= 0)
274
- columns[idx] ??= { navItems: [] }
275
- let { navItems } = columnEntry
276
- if (i === 0) {
277
- navItemLevel1 = navItems[0]
278
- navItems = navItems.slice(1)
279
- }
280
- columns[idx].navItems.push(...navItems)
281
- })
282
- const navItemsByColumnLayout: NavItemsByColumnLayout = {
283
- columns,
284
- navItemLevel1: navItemLevel1!,
285
- isFullWidthCategory,
286
- }
287
- return navItemsByColumnLayout
288
- }
289
- },
290
- )
291
- return navItemsByColumnLayouts
292
- }
293
- type NavItemsByColumnEntries = { columnEntries: ColumnEntry[]; isFullWidthCategory: boolean }[]
294
- type ColumnEntry = { navItems: NavItemComputed[]; columnMap: ColumnMap }
295
- type ColumnMap = Record<number, number>
296
- function getNavItemsByColumnEntries(navItems: NavItemComputed[]): NavItemsByColumnEntries {
297
- const navItemsByColumnEntries: NavItemsByColumnEntries = []
298
- let columnEntries: ColumnEntry[] = []
299
- let columnEntry: ColumnEntry
300
- let isFullWidthCategory: boolean | undefined
301
- navItems.forEach((navItem) => {
302
- if (navItem.level === 1) {
303
- const isFullWidthCategoryPrevious = isFullWidthCategory
304
- isFullWidthCategory = !!navItem.menuModalFullWidth
305
- if (isFullWidthCategoryPrevious !== undefined && isFullWidthCategoryPrevious !== isFullWidthCategory) {
306
- navItemsByColumnEntries.push({ columnEntries, isFullWidthCategory: isFullWidthCategoryPrevious })
307
- columnEntries = []
308
- }
309
- }
310
- assert(isFullWidthCategory !== undefined)
311
- if (navItem.isColumnEntry) {
312
- assert(navItem.level === 1 || navItem.level === 4)
313
- columnEntry = { navItems: [navItem], columnMap: navItem.isColumnEntry }
314
- columnEntries.push(columnEntry)
315
- } else {
316
- assert(navItem.level !== 1)
317
- columnEntry.navItems.push(navItem)
318
- }
319
- })
320
- assert(isFullWidthCategory !== undefined)
321
- navItemsByColumnEntries.push({ columnEntries, isFullWidthCategory })
322
- return navItemsByColumnEntries
323
- }
324
-
325
- type NavItemComputed = ReturnType<typeof getNavItemsWithComputed>[number]
326
- function getNavItemsWithComputed(navItems: NavItem[], currentUrl: string) {
327
- let navItemIdx: number | undefined
328
- const navItemsWithComputed = navItems.map((navItem, i) => {
329
- assert([1, 2, 3, 4].includes(navItem.level), navItem)
330
-
331
- const navItemPrevious = navItems[i - 1]
332
- const navItemNext = navItems[i + 1]
333
-
334
- let isActive = false
335
- if (navItem.url === currentUrl) {
336
- assert(navItem.level === 2, { currentUrl })
337
- assert(navItemIdx === undefined)
338
- navItemIdx = i
339
- isActive = true
340
- }
341
-
342
- const isFirstOfItsKind = navItem.level !== navItemPrevious?.level
343
- const isLastOfItsKind = navItem.level !== navItemNext?.level
344
-
345
- const navItemComputed = {
346
- ...navItem,
347
- isActive,
348
- isRelevant: false,
349
- isFirstOfItsKind,
350
- isLastOfItsKind,
351
- }
352
-
353
- return navItemComputed
354
- })
355
-
356
- // Set `isRelevant`
357
- if (navItemIdx !== undefined) {
358
- for (let i = navItemIdx; i >= 0; i--) {
359
- const navItem = navItemsWithComputed[i]!
360
- navItem.isRelevant = true
361
- if (navItem.level === 1) break
362
- }
363
- for (let i = navItemIdx; i < navItemsWithComputed.length; i++) {
364
- const navItem = navItemsWithComputed[i]!
365
- if (navItem.level === 1) break
366
- navItem.isRelevant = true
367
- }
368
- }
369
-
370
- return navItemsWithComputed
371
- }
372
-
373
- function Chevron(props: React.HTMLProps<SVGSVGElement>) {
374
- return (
375
- <svg viewBox="0 0 512 292.52" xmlns="http://www.w3.org/2000/svg" {...props}>
376
- <path
377
- fill="#aaa"
378
- d="M10.725 82.42L230.125 261.82c6.8 6.8 16.2 10.7 25.9 10.7s19.1-3.9 25.9-10.7l219.4-179.4c14.3-14.3 14.3-37.4 0-51.7s-37.4-14.3-51.7 0l-193.6 153.6-193.6-153.6c-14.3-14.3-37.4-14.3-51.7 0s-14.3 37.5 0 51.7z"
379
- />
380
- </svg>
381
- )
382
- }
File without changes