@brillout/docpress 0.1.14 → 0.1.17

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 (143) hide show
  1. package/dist/{chunk-GBXQT242.js → chunk-ZYYJWJMY.js} +38 -13
  2. package/dist/chunk-ZYYJWJMY.js.map +1 -0
  3. package/dist/{devServer-CXZI7V2M.js → devServer-J2XJQJGT.js} +2 -5
  4. package/dist/{devServer-CXZI7V2M.js.map → devServer-J2XJQJGT.js.map} +1 -1
  5. package/dist/index.d.ts +0 -136
  6. package/dist/index.js +27 -484
  7. package/dist/index.js.map +1 -1
  8. package/package.json +10 -13
  9. package/src/MobileHeader.tsx +68 -0
  10. package/src/PageLayout.css +41 -0
  11. package/src/PageLayout.tsx +37 -0
  12. package/src/algolia/DocSearch.css +29 -0
  13. package/src/algolia/DocSearch.ts +37 -0
  14. package/src/autoScrollNav.ts +22 -0
  15. package/src/cli/devServer.ts +31 -0
  16. package/src/cli/index.ts +29 -0
  17. package/src/components/CodeBlock.tsx +22 -0
  18. package/src/components/DocLink.tsx +108 -0
  19. package/src/components/EditPageNote.tsx +18 -0
  20. package/src/components/HorizontalLine.tsx +20 -0
  21. package/src/components/ImportMeta.tsx +11 -0
  22. package/src/components/Info.tsx +12 -0
  23. package/src/components/Link.tsx +18 -0
  24. package/src/components/Note.tsx +31 -0
  25. package/src/components/P.css +8 -0
  26. package/src/components/P.tsx +8 -0
  27. package/src/components/ReadingRecommendation.tsx +53 -0
  28. package/src/components/RepoLink.tsx +24 -0
  29. package/src/components/Sponsors/companyLogos/ccoli-logo.svg +1 -0
  30. package/src/components/Sponsors/companyLogos/ccoli-text.svg +1 -0
  31. package/{dist/ccoli-CHW3TQKS.svg → src/components/Sponsors/companyLogos/ccoli.svg} +0 -0
  32. package/{dist/contra-WLZBOPBV.svg → src/components/Sponsors/companyLogos/contra.svg} +0 -0
  33. package/{dist/mfqs-2EAEE7N6.svg → src/components/Sponsors/companyLogos/mfqs.svg} +0 -0
  34. package/src/components/Sponsors/label.draft.svg +108 -0
  35. package/{dist/label-MP75CTIA.svg → src/components/Sponsors/label.svg} +0 -0
  36. package/{dist/medalBronze-CO4CTUR4.svg → src/components/Sponsors/medalBronze.svg} +0 -0
  37. package/{dist/medalGold-UP6A73FL.svg → src/components/Sponsors/medalGold.svg} +0 -0
  38. package/{dist/medalSilver-FAPGGOBN.svg → src/components/Sponsors/medalSilver.svg} +0 -0
  39. package/src/components/Sponsors.tsx +242 -0
  40. package/{dist → src}/components/features/FeatureList.css +7 -2
  41. package/src/components/features/FeatureList.tsx +114 -0
  42. package/{dist/chevron-R2IYJD62.svg → src/components/features/chevron.svg} +0 -0
  43. package/src/components/features/initFeatureList.ts +66 -0
  44. package/src/components/index.ts +13 -0
  45. package/src/config/Config.ts +30 -0
  46. package/src/config/getConfig.ts +18 -0
  47. package/src/config/resolveConfig/resolveHeading.ts +0 -0
  48. package/src/config/resolvePageContext.ts +157 -0
  49. package/{dist/Inter-Var-IOAEQULN.ttf → src/css/Inter-Var.ttf} +0 -0
  50. package/src/css/button.css +7 -0
  51. package/src/css/code/block.css +36 -0
  52. package/src/css/code/inline.css +27 -0
  53. package/src/css/code.css +20 -0
  54. package/src/css/colorize-on-hover.css +29 -0
  55. package/src/css/font.css +19 -0
  56. package/src/css/heading.css +25 -0
  57. package/src/css/index.css +11 -0
  58. package/src/css/link.css +17 -0
  59. package/src/css/note.css +26 -0
  60. package/src/css/reset.css +12 -0
  61. package/src/css/table.css +14 -0
  62. package/src/css/tooltip.css +11 -0
  63. package/src/headings.ts +200 -0
  64. package/{dist/changelog-IPI5F42D.svg → src/icons/changelog.svg} +0 -0
  65. package/{dist/discord-JD33TUSF.svg → src/icons/discord.svg} +0 -0
  66. package/{dist/github-P5ZSKN2N.svg → src/icons/github.svg} +0 -0
  67. package/{dist/heart-OINVKOXO.svg → src/icons/heart.svg} +0 -0
  68. package/{dist/twitter-I7DXDN3J.svg → src/icons/twitter.svg} +0 -0
  69. package/src/index.ts +3 -0
  70. package/src/installSectionUrlHashs.ts +50 -0
  71. package/src/markdownHeadingsVitePlugin.ts +128 -0
  72. package/src/navigation/Navigation-highlight.css +41 -0
  73. package/src/navigation/Navigation-items.css +122 -0
  74. package/src/navigation/Navigation-layout.css +118 -0
  75. package/src/navigation/Navigation.client.old.ts +303 -0
  76. package/src/navigation/Navigation.client.ts +19 -0
  77. package/src/navigation/Navigation.css +12 -0
  78. package/src/navigation/Navigation.tsx +228 -0
  79. package/src/navigation/NavigationHeader.tsx +97 -0
  80. package/src/navigation/navigation-fullscreen/NavigationFullscreenButton.css +32 -0
  81. package/src/navigation/navigation-fullscreen/NavigationFullscreenButton.tsx +44 -0
  82. package/{dist/chevron-K3WPYLOP.svg → src/navigation/navigation-fullscreen/chevron.svg} +0 -0
  83. package/{dist/close-IQXTDOHV.svg → src/navigation/navigation-fullscreen/close.svg} +0 -0
  84. package/src/navigation/navigation-fullscreen/initNavigationFullscreen.ts +115 -0
  85. package/src/parseEmojis.ts +33 -0
  86. package/src/renderer/_default.page.client.ts +4 -0
  87. package/src/renderer/_default.page.server.tsx +69 -0
  88. package/src/renderer/usePageContext.tsx +25 -0
  89. package/src/types.ts +2 -0
  90. package/src/utils/Emoji/Emoji.ts +216 -0
  91. package/src/utils/Emoji/assets.ts +9 -0
  92. package/{dist/compass-2RWQU3E4.svg → src/utils/Emoji/compass.svg} +0 -0
  93. package/{dist/engine-6Q6VSCVA.png → src/utils/Emoji/engine.png} +0 -0
  94. package/src/utils/Emoji/index.ts +1 -0
  95. package/{dist/mechanical-arm-TR7IQQMG.svg → src/utils/Emoji/mechanical-arm.svg} +0 -0
  96. package/src/utils/Emoji/mountain.svg +1 -0
  97. package/{dist/road-fork-3WZLW3HB.svg → src/utils/Emoji/road-fork.svg} +0 -0
  98. package/{dist/shield-CU45RG5C.svg → src/utils/Emoji/shield.svg} +0 -0
  99. package/{dist/typescript-ALIPKLRM.svg → src/utils/Emoji/typescript.svg} +0 -0
  100. package/src/utils/assert.ts +39 -0
  101. package/src/utils/client.ts +2 -0
  102. package/src/utils/crawlAllFiles.ts +17 -0
  103. package/src/utils/determineSectionUrlHash.ts +35 -0
  104. package/src/utils/filesystemPathHandling.ts +42 -0
  105. package/src/utils/filter.ts +12 -0
  106. package/src/utils/isBrowser.ts +5 -0
  107. package/src/utils/jsxToTextContent.ts +11 -0
  108. package/src/utils/objectAssign.ts +9 -0
  109. package/src/utils/server.ts +8 -0
  110. package/src/vite.config.ts +44 -0
  111. package/dist/chunk-7HKDCMSZ.js +0 -154
  112. package/dist/chunk-7HKDCMSZ.js.map +0 -1
  113. package/dist/chunk-G2A5MZJA.js +0 -48
  114. package/dist/chunk-G2A5MZJA.js.map +0 -1
  115. package/dist/chunk-GBXQT242.js.map +0 -1
  116. package/dist/chunk-JS5BGVDK.js +0 -178
  117. package/dist/chunk-JS5BGVDK.js.map +0 -1
  118. package/dist/chunk-OEVBWUR6.js +0 -92
  119. package/dist/chunk-OEVBWUR6.js.map +0 -1
  120. package/dist/chunk-TTLAZ2T2.js +0 -8
  121. package/dist/chunk-TTLAZ2T2.js.map +0 -1
  122. package/dist/cli/index.d.ts +0 -1
  123. package/dist/cli/index.js +0 -35
  124. package/dist/cli/index.js.map +0 -1
  125. package/dist/components/features/FeatureList.css.map +0 -1
  126. package/dist/components/features/FeatureList.d.ts +0 -13
  127. package/dist/components/features/FeatureList.js +0 -8
  128. package/dist/components/features/FeatureList.js.map +0 -1
  129. package/dist/components/features/initFeatureList.d.ts +0 -3
  130. package/dist/components/features/initFeatureList.js +0 -60
  131. package/dist/components/features/initFeatureList.js.map +0 -1
  132. package/dist/index.css +0 -121
  133. package/dist/index.css.map +0 -1
  134. package/dist/renderer/_default.page.client.css +0 -263
  135. package/dist/renderer/_default.page.client.css.map +0 -1
  136. package/dist/renderer/_default.page.client.d.ts +0 -1
  137. package/dist/renderer/_default.page.client.js +0 -180
  138. package/dist/renderer/_default.page.client.js.map +0 -1
  139. package/dist/renderer/_default.page.server.css +0 -312
  140. package/dist/renderer/_default.page.server.css.map +0 -1
  141. package/dist/renderer/_default.page.server.d.ts +0 -22
  142. package/dist/renderer/_default.page.server.js +0 -602
  143. package/dist/renderer/_default.page.server.js.map +0 -1
@@ -0,0 +1,19 @@
1
+ import { initNavigationFullscreen } from './navigation-fullscreen/initNavigationFullscreen'
2
+
3
+ activateNavigationMask()
4
+ activateMenuToggle()
5
+ initNavigationFullscreen()
6
+
7
+ function activateMenuToggle() {
8
+ const menuToggle = document.getElementById('menu-toggle')!
9
+ menuToggle.onclick = toggleNavigation
10
+ }
11
+
12
+ function activateNavigationMask() {
13
+ const navigationMask = document.getElementById('navigation-mask')!
14
+ navigationMask.onclick = toggleNavigation
15
+ }
16
+
17
+ function toggleNavigation() {
18
+ document.body.classList.toggle('show-menu')
19
+ }
@@ -0,0 +1,12 @@
1
+ @import './Navigation-layout.css';
2
+ @import './Navigation-items.css';
3
+ @import './Navigation-highlight.css';
4
+
5
+ #navigation-container {
6
+ --background-color: #f0f0f0;
7
+ padding-bottom: 70px;
8
+ }
9
+
10
+ html.navigation-fullscreen #detached-note {
11
+ display: none;
12
+ }
@@ -0,0 +1,228 @@
1
+ export { Navigation }
2
+ export { NavigationMask }
3
+
4
+ import React from 'react'
5
+ import { NavigationHeader } from './NavigationHeader'
6
+ import { Heading } from '../headings'
7
+ import { assert, Emoji } from '../utils/server'
8
+ import './Navigation.css'
9
+ import { NavigationFullscreenClose } from './navigation-fullscreen/NavigationFullscreenButton'
10
+
11
+ function Navigation({
12
+ pageContext
13
+ }: {
14
+ pageContext: {
15
+ headingsWithSubHeadings: Heading[]
16
+ urlPathname: string
17
+ isDetachedPage: boolean
18
+ }
19
+ }) {
20
+ const { isDetachedPage } = pageContext
21
+ return (
22
+ <>
23
+ <div id="navigation-container">
24
+ <NavigationHeader />
25
+ {isDetachedPage && <DetachedPageNote />}
26
+ <NavigationContent pageContext={pageContext} />
27
+ {/* <ScrollOverlay /> */}
28
+ <NavigationFullscreenClose />
29
+ </div>
30
+ </>
31
+ )
32
+ }
33
+
34
+ function NavigationMask() {
35
+ return <div id="navigation-mask" />
36
+ }
37
+
38
+ function NavigationContent({
39
+ pageContext
40
+ }: {
41
+ pageContext: {
42
+ headingsWithSubHeadings: Heading[]
43
+ urlPathname: string
44
+ isDetachedPage: boolean
45
+ }
46
+ }) {
47
+ const headings = getHeadingsWithComputedProps(pageContext)
48
+ const headingsGrouped = groupHeadings(headings)
49
+ return (
50
+ <div id="navigation-content">
51
+ <div className="nav-column" style={{ position: 'relative' }}>
52
+ {headingsGrouped.map((headingsH1, i) => (
53
+ <div className="nav-h1-group" key={i}>
54
+ <Heading heading={headingsH1} />
55
+ {headingsH1.headings.map((heading, j) => (
56
+ <Heading heading={heading} key={j} />
57
+ ))}
58
+ </div>
59
+ ))}
60
+ </div>
61
+ </div>
62
+ )
63
+ }
64
+
65
+ function Heading({
66
+ heading
67
+ }: {
68
+ heading: {
69
+ level: number
70
+ url?: string
71
+ titleInNav: string | JSX.Element
72
+ computed: {
73
+ isActive: boolean
74
+ isActiveFirst: boolean
75
+ isActiveLast: boolean
76
+ isChildOfListHeading: boolean
77
+ isFirstOfItsKind: boolean
78
+ isLastOfItsKind: boolean
79
+ }
80
+ }
81
+ }) {
82
+ assert([1, 2, 3, 4].includes(heading.level), heading)
83
+ return (
84
+ <a
85
+ className={[
86
+ 'nav-item',
87
+ 'nav-item-h' + heading.level,
88
+ heading.computed.isActive && ' is-active',
89
+ heading.computed.isActiveFirst && ' is-active-first',
90
+ heading.computed.isActiveLast && ' is-active-last',
91
+ heading.computed.isChildOfListHeading && 'nav-item-parent-is-list-heading',
92
+ heading.computed.isFirstOfItsKind && 'nav-item-first-of-its-kind',
93
+ heading.computed.isLastOfItsKind && 'nav-item-last-of-its-kind'
94
+ ]
95
+ .filter(Boolean)
96
+ .join(' ')}
97
+ href={heading.url || undefined}
98
+ >
99
+ {/* <span className="nav-item-text">{heading.titleInNav}</span> */}
100
+ {heading.titleInNav}
101
+ </a>
102
+ )
103
+ }
104
+
105
+ function groupHeadings<T extends { level: number }>(headings: T[]) {
106
+ const headingsGrouped: (T & { headings: T[] })[] = []
107
+ headings.forEach((heading) => {
108
+ if (heading.level === 1) {
109
+ headingsGrouped.push({ ...heading, headings: [] })
110
+ } else {
111
+ headingsGrouped[headingsGrouped.length - 1].headings.push(heading)
112
+ }
113
+ })
114
+ return headingsGrouped
115
+ }
116
+
117
+ function getHeadingsWithComputedProps(pageContext: {
118
+ headingsWithSubHeadings: Heading[]
119
+ urlPathname: string
120
+ isDetachedPage: boolean
121
+ }) {
122
+ const { headingsWithSubHeadings, urlPathname } = pageContext
123
+ return headingsWithSubHeadings.map((heading, i) => {
124
+ assert([1, 2, 3, 4].includes(heading.level), heading)
125
+
126
+ const headingPrevious = headingsWithSubHeadings[i - 1]
127
+ const headingNext = headingsWithSubHeadings[i + 1]
128
+
129
+ let isActiveFirst = false
130
+ let isActiveLast = false
131
+ let isActive = false
132
+ if (heading.url === urlPathname) {
133
+ assert(heading.level === 2, { urlPathname })
134
+ isActive = true
135
+ isActiveFirst = true
136
+ if (headingNext?.level !== 3) {
137
+ isActiveLast = true
138
+ }
139
+ }
140
+ if (heading.level === 3) {
141
+ isActive = true
142
+ if (headingNext?.level !== 3) {
143
+ isActiveLast = true
144
+ }
145
+ }
146
+
147
+ const isFirstOfItsKind = heading.level !== headingPrevious?.level
148
+ const isLastOfItsKind = heading.level !== headingNext?.level
149
+ const isChildOfListHeading = !!heading.parentHeadings[0]?.isListTitle
150
+
151
+ return {
152
+ ...heading,
153
+ computed: {
154
+ isActive,
155
+ isActiveFirst,
156
+ isActiveLast,
157
+ isFirstOfItsKind,
158
+ isLastOfItsKind,
159
+ isChildOfListHeading
160
+ }
161
+ }
162
+ })
163
+ }
164
+
165
+ function ScrollOverlay() {
166
+ // const width = '1px'
167
+ // const color = '#aaa'
168
+ return (
169
+ <div
170
+ id="scroll-overlay"
171
+ style={{
172
+ pointerEvents: 'none',
173
+ position: 'absolute',
174
+ left: '0',
175
+ width: '100%',
176
+ /*
177
+ background: `linear-gradient(to right, ${color} ${width}, transparent ${width}) 0 0,
178
+ linear-gradient(to right, ${color} ${width}, transparent ${width}) 0 100%,
179
+ linear-gradient(to left, ${color} ${width}, transparent ${width}) 100% 0,
180
+ linear-gradient(to left, ${color} ${width}, transparent ${width}) 100% 100%,
181
+ linear-gradient(to bottom, ${color} ${width}, transparent ${width}) 0 0,
182
+ linear-gradient(to bottom, ${color} ${width}, transparent ${width}) 100% 0,
183
+ linear-gradient(to top, ${color} ${width}, transparent ${width}) 0 100%,
184
+ linear-gradient(to top, ${color} ${width}, transparent ${width}) 100% 100%`,
185
+ //*/
186
+ //borderRight: `5px solid ${color}`,
187
+ borderRight: `3px solid #666`,
188
+ //border: `1px solid ${color}`,
189
+ boxSizing: 'border-box',
190
+ // backgroundColor: 'rgba(0,0,0,0.03)',
191
+ backgroundRepeat: 'no-repeat',
192
+
193
+ backgroundSize: '10px 10px'
194
+ }}
195
+ />
196
+ )
197
+ }
198
+
199
+ function DetachedPageNote() {
200
+ return (
201
+ <div
202
+ id="detached-note"
203
+ style={{
204
+ backgroundColor: 'var(--background-color)',
205
+ textAlign: 'left',
206
+ marginLeft: 10,
207
+ marginRight: 10,
208
+ marginTop: 30,
209
+ marginBottom: -8,
210
+ borderRadius: 5,
211
+ padding: 10
212
+ }}
213
+ >
214
+ <Emoji name="info" />{' '}
215
+ <b>
216
+ <em>Detached</em>
217
+ </b>
218
+ <span
219
+ style={{
220
+ opacity: 0.8
221
+ }}
222
+ >
223
+ {' '}
224
+ &mdash; this page isn't listed in the navigation menu below.
225
+ </span>
226
+ </div>
227
+ )
228
+ }
@@ -0,0 +1,97 @@
1
+ import React from 'react'
2
+ import iconGithub from '../icons/github.svg'
3
+ import iconTwitter from '../icons/twitter.svg'
4
+ import iconDiscord from '../icons/discord.svg'
5
+ import iconChangelog from '../icons/changelog.svg'
6
+ import { usePageContext } from '../renderer/usePageContext'
7
+
8
+ export { NavigationHeader }
9
+
10
+ function NavigationHeader() {
11
+ const pageContext = usePageContext()
12
+ return (
13
+ <div
14
+ id="navigation-header"
15
+ style={{
16
+ display: 'flex',
17
+ flexDirection: 'column',
18
+ alignItems: 'center',
19
+ marginBottom: -5
20
+ }}
21
+ >
22
+ <a
23
+ id="navigation-header-logo"
24
+ style={{
25
+ display: 'flex',
26
+ alignItems: 'center',
27
+ color: 'inherit',
28
+ justifyContent: 'left',
29
+ textDecoration: 'none',
30
+ paddingTop: 12,
31
+ paddingBottom: 7
32
+ }}
33
+ href="/"
34
+ >
35
+ {pageContext.config.navHeader}
36
+ </a>
37
+ <Links />
38
+ </div>
39
+ )
40
+ }
41
+
42
+ function Links() {
43
+ const pageContext = usePageContext()
44
+ const { projectInfo } = pageContext.config
45
+ return (
46
+ <div
47
+ style={{
48
+ display: 'flex',
49
+ alignItems: 'center',
50
+ paddingTop: 0,
51
+ justifyContent: 'left'
52
+ }}
53
+ >
54
+ <SocialLink className="decolorize-4" icon={iconGithub} href={projectInfo.githubRepository} />
55
+ <SocialLink className="decolorize-6" icon={iconDiscord} href={projectInfo.discordInvite} />
56
+ <SocialLink className="decolorize-7" icon={iconTwitter} href={projectInfo.twitterProfile} />
57
+ <div id="docsearch-desktop" />
58
+ <ChangelogButton />
59
+ </div>
60
+ )
61
+ }
62
+
63
+ function ChangelogButton() {
64
+ const pageContext = usePageContext()
65
+ const { projectInfo } = pageContext.config
66
+ return (
67
+ <a
68
+ href={`${projectInfo.githubRepository}/blob/main/CHANGELOG.md`}
69
+ className="button colorize-on-hover"
70
+ style={{
71
+ display: 'flex',
72
+ alignItems: 'center',
73
+ padding: '1px 7px',
74
+ marginLeft: 2,
75
+ fontSize: '0.97em',
76
+ color: 'inherit'
77
+ }}
78
+ >
79
+ <span className="decolorize-7">v{projectInfo.projectVersion}</span>
80
+ <img className="decolorize-6" src={iconChangelog} height={16} style={{ marginLeft: 5 }} />
81
+ </a>
82
+ )
83
+ }
84
+
85
+ function SocialLink({ className, icon, href }: { className: string; icon: string; href: string }) {
86
+ return (
87
+ <>
88
+ <a
89
+ className={'colorize-on-hover ' + className}
90
+ href={href}
91
+ style={{ padding: 3, display: 'inline-block', lineHeight: 0 }}
92
+ >
93
+ <img src={icon} height="20" style={{}} />
94
+ </a>
95
+ </>
96
+ )
97
+ }
@@ -0,0 +1,32 @@
1
+ :root {
2
+ --navigation-fullscreen-button-width: 20px;
3
+ }
4
+ #navigation-fullscreen-button {
5
+ width: var(--navigation-fullscreen-button-width);
6
+ position: relative;
7
+ z-index: 2;
8
+ }
9
+ #navigation-wrapper:hover + #navigation-fullscreen-button > div > div,
10
+ #navigation-fullscreen-button:hover > div > div {
11
+ left: 0px;
12
+ }
13
+ #navigation-fullscreen-button > div > div {
14
+ transition: all 0.3s ease-in-out;
15
+ left: -20px;
16
+ position: absolute;
17
+ height: 100%;
18
+ width: 100%;
19
+ background-color: #eee !important;
20
+ background: url('./chevron.svg');
21
+ background-repeat: no-repeat;
22
+ background-position: center center;
23
+ }
24
+
25
+ html:not(.navigation-fullscreen) #navigation-fullscreen-close {
26
+ display: none;
27
+ }
28
+
29
+ html.navigation-fullscreen #page-content {
30
+ /* Make `Ctrl-F` browser search only crawl the navigation menu */
31
+ visibility: hidden;
32
+ }
@@ -0,0 +1,44 @@
1
+ export { NavigationFullscreenButton }
2
+ export { NavigationFullscreenClose }
3
+
4
+ import React from 'react'
5
+ import './NavigationFullscreenButton.css'
6
+ import closeIcon from './close.svg'
7
+
8
+ function NavigationFullscreenButton() {
9
+ return (
10
+ <>
11
+ <a id="navigation-fullscreen-button">
12
+ <div
13
+ style={{
14
+ position: 'fixed',
15
+ cursor: 'pointer',
16
+ height: '100vh',
17
+ width: 20,
18
+ overflow: 'hidden'
19
+ }}
20
+ >
21
+ <div></div>
22
+ </div>
23
+ <div
24
+ style={{ position: 'fixed', height: '100vh', width: 20 }}
25
+ aria-label="Press <Esc>"
26
+ data-balloon-pos="right"
27
+ ></div>
28
+ </a>
29
+ </>
30
+ )
31
+ }
32
+
33
+ function NavigationFullscreenClose() {
34
+ return (
35
+ <a
36
+ id="navigation-fullscreen-close"
37
+ style={{ position: 'fixed', top: 11, right: 15, zIndex: 10 }}
38
+ aria-label="Press <Esc>"
39
+ data-balloon-pos="left"
40
+ >
41
+ <img src={closeIcon} height={50} width={50} style={{ display: 'block' }} />
42
+ </a>
43
+ )
44
+ }
@@ -0,0 +1,115 @@
1
+ export { initNavigationFullscreen }
2
+
3
+ import { assert } from '../../utils/client'
4
+
5
+ let scrollPositionBeforeToggle: number = 0
6
+
7
+ function initNavigationFullscreen() {
8
+ updateColumnWidth()
9
+ window.addEventListener('resize', updateColumnWidth, { passive: true })
10
+ document.getElementById('navigation-fullscreen-button')!.onclick = toggleNavExpend
11
+ document.getElementById('navigation-fullscreen-close')!.onclick = toggleNavExpend
12
+ document.addEventListener(
13
+ // We don't use keydown to not interfere with user pressing `<Esc>` for closing the browser's `<Ctrl-F>` search diablog, see https://stackoverflow.com/questions/66595035/how-to-detect-escape-key-if-search-bar-of-browser-is-open
14
+ 'keydown',
15
+ (ev) => {
16
+ if (ev.key === 'Escape') toggleNavExpend()
17
+ },
18
+ false
19
+ )
20
+ }
21
+
22
+ function toggleNavExpend() {
23
+ const navContainer = document.getElementById('navigation-container')!
24
+ const scrollPos = navContainer.scrollTop
25
+ document.documentElement.classList.toggle('navigation-fullscreen')
26
+ if (scrollPositionBeforeToggle !== undefined) {
27
+ navContainer.scrollTop = scrollPositionBeforeToggle
28
+ }
29
+ scrollPositionBeforeToggle = scrollPos
30
+ }
31
+
32
+ function updateColumnWidth() {
33
+ const navMinWidth = 299
34
+ const navH1Groups = Array.from(document.querySelectorAll('.nav-h1-group'))
35
+ const numberOfColumnsMax = navH1Groups.length
36
+
37
+ const widthAvailable = getViewportWidth()
38
+ const numberOfColumns = Math.max(1, Math.min(numberOfColumnsMax, Math.floor(widthAvailable / navMinWidth)))
39
+
40
+ let columns = navH1Groups.map((navH1Group) => {
41
+ const column = [
42
+ {
43
+ element: navH1Group,
44
+ elementHeight: navH1Group.children.length
45
+ }
46
+ ]
47
+ return column
48
+ })
49
+
50
+ mergeColumns(columns, numberOfColumns)
51
+
52
+ const navContent = document.getElementById('navigation-content')!
53
+
54
+ Array.from(navContent.children).forEach((child) => {
55
+ assert(child.className === 'nav-column')
56
+ })
57
+ navContent.innerHTML = ''
58
+
59
+ columns.forEach((column) => {
60
+ const columnEl = document.createElement('div')
61
+ columnEl.className = 'nav-column'
62
+ column.forEach(({ element }) => {
63
+ columnEl.appendChild(element)
64
+ })
65
+ navContent.appendChild(columnEl)
66
+ })
67
+
68
+ const navItemMaxWidth = 350
69
+ navContent.style.maxWidth = `${numberOfColumns * navItemMaxWidth}px`
70
+ }
71
+ function getViewportWidth(): number {
72
+ // `window.innerWidth` inlcudes scrollbar width: https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
73
+ return document.documentElement.clientWidth
74
+ }
75
+
76
+ function mergeColumns<T>(columns: { element: T; elementHeight: number }[][], maxNumberOfColumns: number) {
77
+ assert(columns.length > 0)
78
+ assert(maxNumberOfColumns > 0)
79
+ if (columns.length <= maxNumberOfColumns) {
80
+ return columns
81
+ }
82
+
83
+ let mergeCandidate = {
84
+ i: -1,
85
+ mergeHeight: Infinity
86
+ }
87
+ for (let i = 0; i <= columns.length - 2; i++) {
88
+ const column1 = columns[i + 0]
89
+ const column2 = columns[i + 1]
90
+ const column1Height = sum(column1.map((c) => c.elementHeight))
91
+ const column2Height = sum(column2.map((c) => c.elementHeight))
92
+ const mergeHeight = column1Height + column2Height
93
+ if (mergeCandidate.mergeHeight > mergeHeight) {
94
+ mergeCandidate = {
95
+ i,
96
+ mergeHeight
97
+ }
98
+ }
99
+ }
100
+
101
+ {
102
+ const { i } = mergeCandidate
103
+ assert(-1 < i && i < columns.length - 1, { i, columnsLength: columns.length, maxNumberOfColumns })
104
+ columns[i] = [...columns[i], ...columns[i + 1]]
105
+ columns.splice(i + 1, 1)
106
+ }
107
+
108
+ mergeColumns(columns, maxNumberOfColumns)
109
+ }
110
+
111
+ function sum(arr: number[]): number {
112
+ let total = 0
113
+ arr.forEach((n) => (total += n))
114
+ return total
115
+ }
@@ -0,0 +1,33 @@
1
+ export { parseEmojis }
2
+
3
+ import twemoji from 'twemoji'
4
+
5
+ const emojiList = {
6
+ // https://emojipedia.org/no-entry/
7
+ ':no_entry:': 0x26d4,
8
+ // https://emojipedia.org/warning/
9
+ ':warning:': 0x26a0,
10
+ // https://emojipedia.org/trophy/
11
+ ':trophy:': 0x1f3c6
12
+ /*
13
+ // https://emojipedia.org/red-heart/
14
+ ':heart:': 0x2764,
15
+ */
16
+ }
17
+
18
+ function parseEmojis(html: string) {
19
+ Object.entries(emojiList).forEach(([shortcode, codepoint]) => {
20
+ if (!html.includes(shortcode)) {
21
+ return
22
+ }
23
+ const emojiStr = twemoji.convert.fromCodePoint(codepoint as any)
24
+ let emojiImg: any = twemoji.parse(emojiStr, {
25
+ folder: 'svg',
26
+ ext: '.svg'
27
+ })
28
+ const style = 'height: 1.275em; width: 1.275em; vertical-align: -20%'
29
+ emojiImg = emojiImg.replace('<img class="emoji" ', `<img style="${style}" `)
30
+ html = html.split(shortcode).join(emojiImg)
31
+ })
32
+ return html
33
+ }
@@ -0,0 +1,4 @@
1
+ import '../css/index.css'
2
+ import '../autoScrollNav'
3
+ import '../installSectionUrlHashs'
4
+ import '../navigation/Navigation.client'
@@ -0,0 +1,69 @@
1
+ import ReactDOMServer from 'react-dom/server'
2
+ import React from 'react'
3
+ import { escapeInject, dangerouslySkipEscape } from 'vite-plugin-ssr'
4
+ import { PageLayout } from '../PageLayout'
5
+ import { resolvePageContext, PageContextOriginal } from '../config/resolvePageContext'
6
+ import { getDocSearchJS, getDocSearchCSS } from '../algolia/DocSearch'
7
+ import { parseEmojis } from '../parseEmojis'
8
+ import { assert } from '../utils/server'
9
+
10
+ export { render }
11
+
12
+ async function render(pageContextOriginal: PageContextOriginal) {
13
+ const { Page } = pageContextOriginal
14
+ const pageContextResolved = resolvePageContext(pageContextOriginal)
15
+
16
+ const page = (
17
+ <PageLayout pageContext={pageContextResolved}>
18
+ <Page />
19
+ </PageLayout>
20
+ )
21
+
22
+ const descriptionTag = pageContextResolved.isLandingPage
23
+ ? dangerouslySkipEscape(`<meta name="description" content="${pageContextResolved.meta.tagline}" />`)
24
+ : ''
25
+
26
+ const docSearchJS = getDocSearchJS(pageContextResolved)
27
+ const docSearchCSS = getDocSearchCSS(pageContextResolved)
28
+
29
+ let pageHtml = ReactDOMServer.renderToString(page)
30
+ pageHtml = parseEmojis(pageHtml)
31
+
32
+ return escapeInject`<!DOCTYPE html>
33
+ <html>
34
+ <head>
35
+ <meta charset="UTF-8" />
36
+ <link rel="icon" href="${pageContextResolved.meta.faviconUrl}" />
37
+ <title>${pageContextResolved.meta.title}</title>
38
+ ${descriptionTag}
39
+ <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
40
+ ${docSearchCSS}
41
+ ${getOpenGraphTags(pageContextOriginal.urlPathname, pageContextResolved.meta)}
42
+ </head>
43
+ <body>
44
+ <div id="page-view">${dangerouslySkipEscape(pageHtml)}</div>
45
+ ${docSearchJS}
46
+ </body>
47
+ </html>`
48
+ }
49
+
50
+ function getOpenGraphTags(
51
+ url: string,
52
+ meta: { title: string; tagline: string; websiteUrl: string; twitterHandle: string; bannerUrl?: string }
53
+ ) {
54
+ const { title, tagline, websiteUrl, twitterHandle, bannerUrl } = meta
55
+
56
+ assert(url.startsWith('/'))
57
+ if (url !== '/' || !bannerUrl) return ''
58
+
59
+ // See view-source:https://vitejs.dev/
60
+ return escapeInject`
61
+ <meta property="og:type" content="website">
62
+ <meta property="og:title" content="${title}">
63
+ <meta property="og:image" content="${bannerUrl}">
64
+ <meta property="og:url" content="${websiteUrl}">
65
+ <meta property="og:description" content="${tagline}">
66
+ <meta name="twitter:card" content="summary_large_image">
67
+ <meta name="twitter:site" content="${twitterHandle}">
68
+ `
69
+ }
@@ -0,0 +1,25 @@
1
+ // `usePageContext` allows us to access `pageContext` in any React component.
2
+ // More infos: https://vite-plugin-ssr.com/pageContext-anywhere
3
+
4
+ import React, { useContext } from 'react'
5
+ import type { PageContextResolved } from '../config/resolvePageContext'
6
+
7
+ export { PageContextProvider }
8
+ export { usePageContext }
9
+
10
+ const Context = React.createContext<PageContextResolved>(undefined as any)
11
+
12
+ function PageContextProvider({
13
+ pageContext,
14
+ children
15
+ }: {
16
+ pageContext: PageContextResolved
17
+ children: React.ReactNode
18
+ }) {
19
+ return <Context.Provider value={pageContext}>{children}</Context.Provider>
20
+ }
21
+
22
+ function usePageContext(): PageContextResolved {
23
+ const pageContext = useContext(Context)
24
+ return pageContext
25
+ }
package/src/types.ts ADDED
@@ -0,0 +1,2 @@
1
+ export type { Config } from './config/Config'
2
+ export type { HeadingDefinition, HeadingWithoutLink } from './headings'