@brillout/docpress 0.5.39 → 0.5.40-commit-51be4fa

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/MobileHeader.tsx +68 -0
  2. package/PageLayout.css +42 -0
  3. package/PageLayout.tsx +39 -0
  4. package/algolia/DocSearch.css +34 -0
  5. package/algolia/DocSearch.ts +62 -0
  6. package/autoScrollNav.ts +36 -0
  7. package/components/CodeBlockTransformer.css +9 -0
  8. package/components/CodeBlockTransformer.tsx +18 -0
  9. package/components/Comment.tsx +7 -0
  10. package/components/Consulting.tsx +47 -0
  11. package/components/Contributors.tsx +113 -0
  12. package/components/EditPageNote.tsx +18 -0
  13. package/components/HorizontalLine.tsx +20 -0
  14. package/components/ImportMeta.tsx +11 -0
  15. package/components/Link.tsx +144 -0
  16. package/components/Note.css +54 -0
  17. package/components/Note.tsx +78 -0
  18. package/components/P.css +8 -0
  19. package/components/P.tsx +8 -0
  20. package/components/ReadingRecommendation.tsx +56 -0
  21. package/components/RepoLink.tsx +24 -0
  22. package/components/Sponsors/label.draft.svg +108 -0
  23. package/components/Sponsors.tsx +218 -0
  24. package/components/Supporters.tsx +136 -0
  25. package/{dist/components → components}/features/FeatureList.css +10 -2
  26. package/components/features/FeatureList.tsx +114 -0
  27. package/components/features/initFeatureList.ts +66 -0
  28. package/components/index.ts +15 -0
  29. package/config/getConfig.ts +18 -0
  30. package/config/resolveConfig/resolveHeading.ts +0 -0
  31. package/config/resolvePageContext.ts +186 -0
  32. package/css/button.css +7 -0
  33. package/css/code/block.css +36 -0
  34. package/css/code/inline.css +27 -0
  35. package/css/code.css +20 -0
  36. package/css/colorize-on-hover.css +29 -0
  37. package/css/font.css +25 -0
  38. package/css/heading.css +45 -0
  39. package/css/index.css +12 -0
  40. package/css/link.css +17 -0
  41. package/css/reset.css +12 -0
  42. package/css/table.css +14 -0
  43. package/css/tooltip.css +11 -0
  44. package/data/maintainersList.tsx +92 -0
  45. package/data/sponsorsList.ts +147 -0
  46. package/dist/markdownHeadingsVitePlugin.d.ts +13 -0
  47. package/dist/markdownHeadingsVitePlugin.js +170 -0
  48. package/dist/utils/assert.d.ts +6 -0
  49. package/dist/utils/assert.js +48 -0
  50. package/dist/utils/determineSectionUrlHash.d.ts +4 -0
  51. package/dist/utils/determineSectionUrlHash.js +38 -0
  52. package/dist/vite.config.d.ts +3 -0
  53. package/dist/vite.config.js +32 -0
  54. package/index.ts +4 -0
  55. package/installSectionUrlHashs.ts +60 -0
  56. package/markdownHeadingsVitePlugin.ts +150 -0
  57. package/navigation/Navigation-highlight.css +41 -0
  58. package/navigation/Navigation-items.css +119 -0
  59. package/navigation/Navigation-layout.css +127 -0
  60. package/navigation/Navigation.client.ts +43 -0
  61. package/navigation/Navigation.css +3 -0
  62. package/navigation/Navigation.tsx +211 -0
  63. package/navigation/NavigationHeader.tsx +111 -0
  64. package/navigation/navigation-fullscreen/NavigationFullscreenButton.css +32 -0
  65. package/navigation/navigation-fullscreen/NavigationFullscreenButton.tsx +44 -0
  66. package/navigation/navigation-fullscreen/initNavigationFullscreen.ts +116 -0
  67. package/package.json +26 -48
  68. package/parseEmojis.ts +35 -0
  69. package/parseTitle.ts +139 -0
  70. package/renderer/client.ts +4 -0
  71. package/renderer/onRenderHtml.tsx +69 -0
  72. package/renderer/usePageContext.tsx +25 -0
  73. package/tsconfig.json +15 -0
  74. package/tsconfig.vite-config.json +7 -0
  75. package/types/Config.ts +46 -0
  76. package/types/Heading.ts +49 -0
  77. package/utils/Emoji/Emoji.ts +224 -0
  78. package/utils/Emoji/assets.ts +9 -0
  79. package/utils/Emoji/index.ts +1 -0
  80. package/utils/Emoji/mountain.svg +1 -0
  81. package/utils/assert.ts +51 -0
  82. package/utils/client.ts +2 -0
  83. package/utils/determineSectionUrlHash.ts +44 -0
  84. package/utils/filesystemPathHandling.ts +42 -0
  85. package/utils/filter.ts +12 -0
  86. package/utils/isBrowser.ts +5 -0
  87. package/utils/jsxToTextContent.ts +11 -0
  88. package/utils/objectAssign.ts +9 -0
  89. package/utils/server.ts +7 -0
  90. package/vite.config.ts +36 -0
  91. package/bin.js +0 -3
  92. package/dist/chunk-2ZTPUQGS.js +0 -58
  93. package/dist/chunk-3QC7HYIF.js +0 -7
  94. package/dist/chunk-MGOI4AFO.js +0 -165
  95. package/dist/chunk-NVJING6T.js +0 -91
  96. package/dist/chunk-QWL3MA4E.js +0 -171
  97. package/dist/chunk-UN23G34B.js +0 -157
  98. package/dist/cli/index.d.ts +0 -1
  99. package/dist/cli/index.js +0 -34
  100. package/dist/components/features/FeatureList.d.ts +0 -13
  101. package/dist/components/features/FeatureList.js +0 -7
  102. package/dist/components/features/initFeatureList.d.ts +0 -3
  103. package/dist/components/features/initFeatureList.js +0 -59
  104. package/dist/devServer-JKH6U5PF.js +0 -36
  105. package/dist/index.css +0 -120
  106. package/dist/index.d.ts +0 -225
  107. package/dist/index.js +0 -948
  108. package/dist/renderer/_default.page.client.css +0 -318
  109. package/dist/renderer/_default.page.client.d.ts +0 -1
  110. package/dist/renderer/_default.page.client.js +0 -218
  111. package/dist/renderer/_default.page.server.css +0 -310
  112. package/dist/renderer/_default.page.server.d.ts +0 -22
  113. package/dist/renderer/_default.page.server.js +0 -665
  114. package/readme.md +0 -5
  115. /package/{dist/label-MP75CTIA.svg → components/Sponsors/label.svg} +0 -0
  116. /package/{dist/medalBronze-CO4CTUR4.svg → components/Sponsors/medalBronze.svg} +0 -0
  117. /package/{dist/medalGold-UP6A73FL.svg → components/Sponsors/medalGold.svg} +0 -0
  118. /package/{dist/medalSilver-FAPGGOBN.svg → components/Sponsors/medalSilver.svg} +0 -0
  119. /package/{dist/chevron-R2IYJD62.svg → components/features/chevron.svg} +0 -0
  120. /package/{dist/Inter-Var-IOAEQULN.ttf → css/Inter-Var.ttf} +0 -0
  121. /package/{dist/alignable-B4QZV4X7.svg → data/sponsorsList/companyLogos/alignable.svg} +0 -0
  122. /package/{dist/bluefin-JQABZFGV.svg → data/sponsorsList/companyLogos/bluefin.svg} +0 -0
  123. /package/{dist/burdaforward-EUGURYZY.png → data/sponsorsList/companyLogos/burdaforward.png} +0 -0
  124. /package/{dist/contra-WLZBOPBV.svg → data/sponsorsList/companyLogos/contra.svg} +0 -0
  125. /package/{dist/ecosia-OYRLTR5T.svg → data/sponsorsList/companyLogos/ecosia.svg} +0 -0
  126. /package/{dist/inlang-GFRWND6X.png → data/sponsorsList/companyLogos/inlang.png} +0 -0
  127. /package/{dist/optimizers-SFEZF3NW.svg → data/sponsorsList/companyLogos/optimizers.svg} +0 -0
  128. /package/{dist/sourcegraph-YR2HADLS.svg → data/sponsorsList/companyLogos/sourcegraph.svg} +0 -0
  129. /package/{dist/changelog-IPI5F42D.svg → icons/changelog.svg} +0 -0
  130. /package/{dist/discord-JD33TUSF.svg → icons/discord.svg} +0 -0
  131. /package/{dist/github-P5ZSKN2N.svg → icons/github.svg} +0 -0
  132. /package/{dist/heart-OINVKOXO.svg → icons/heart.svg} +0 -0
  133. /package/{dist/languages-KXPKJFQL.svg → icons/languages.svg} +0 -0
  134. /package/{dist/people-72KKQHU4.svg → icons/people.svg} +0 -0
  135. /package/{dist/twitter-I7DXDN3J.svg → icons/twitter.svg} +0 -0
  136. /package/{dist/chevron-K3WPYLOP.svg → navigation/navigation-fullscreen/chevron.svg} +0 -0
  137. /package/{dist/close-IQXTDOHV.svg → navigation/navigation-fullscreen/close.svg} +0 -0
  138. /package/{dist/compass-2RWQU3E4.svg → utils/Emoji/compass.svg} +0 -0
  139. /package/{dist/engine-6Q6VSCVA.png → utils/Emoji/engine.png} +0 -0
  140. /package/{dist/mechanical-arm-TR7IQQMG.svg → utils/Emoji/mechanical-arm.svg} +0 -0
  141. /package/{dist/road-fork-3WZLW3HB.svg → utils/Emoji/road-fork.svg} +0 -0
  142. /package/{dist/shield-CU45RG5C.svg → utils/Emoji/shield.svg} +0 -0
  143. /package/{dist/typescript-ALIPKLRM.svg → utils/Emoji/typescript.svg} +0 -0
@@ -0,0 +1,150 @@
1
+ export { markdownHeadingsVitePlugin }
2
+ export type { MarkdownHeading }
3
+
4
+ import { assert } from './utils/assert.js'
5
+ import { determineSectionUrlHash } from './utils/determineSectionUrlHash.js'
6
+ import os from 'os'
7
+
8
+ type MarkdownHeading = {
9
+ title: string
10
+ headingId: string | null
11
+ headingLevel: number
12
+ titleAddendum?: string
13
+ }
14
+
15
+ function markdownHeadingsVitePlugin() {
16
+ return {
17
+ name: 'mdx-headings',
18
+ enforce: 'pre',
19
+ transform: async (code: string, id: string) => {
20
+ if (!id.endsWith('+Page.mdx')) {
21
+ return
22
+ }
23
+ const codeNew = transform(code)
24
+ return codeNew
25
+ }
26
+ }
27
+ }
28
+
29
+ function transform(code: string) {
30
+ const headings: MarkdownHeading[] = []
31
+ let isCodeBlock = false
32
+ let codeNew = code
33
+ .split('\n')
34
+ .map((line) => {
35
+ // Skip code blocks, e.g.
36
+ // ~~~md
37
+ // # Markdown Example
38
+ // Bla
39
+ // ~~~
40
+ if (line.startsWith('~~~') || line.startsWith('```')) {
41
+ isCodeBlock = !isCodeBlock
42
+ return line
43
+ }
44
+ if (isCodeBlock) {
45
+ return line
46
+ }
47
+
48
+ if (line.startsWith('#')) {
49
+ const { headingId, headingLevel, title, headingHtml } = parseMarkdownHeading(line)
50
+ headings.push({ headingId, headingLevel, title })
51
+ return headingHtml
52
+ }
53
+
54
+ return line
55
+ })
56
+ .join('\n')
57
+ const headingsExportCode = `export const headings = [${headings
58
+ .map((heading) => JSON.stringify(heading))
59
+ .join(', ')}];`
60
+ codeNew += `\n\n${headingsExportCode}\n`
61
+ return codeNew
62
+ }
63
+
64
+ function parseMarkdownHeading(line: string): MarkdownHeading & { headingHtml: string } {
65
+ const [lineBegin, ...lineWords] = line.split(' ')
66
+ assert(lineBegin.split('#').join('') === '', { line, lineWords })
67
+ const headingLevel = lineBegin.length
68
+
69
+ const titleMdx = lineWords.join(' ')
70
+ assert(!titleMdx.startsWith(' '), { line, lineWords })
71
+ assert(titleMdx, { line, lineWords })
72
+
73
+ const headingMdx = {
74
+ title: titleMdx,
75
+ anchor: titleMdx
76
+ }
77
+ {
78
+ // Support custom anchor like: `## title{#custom-anchor}`
79
+ const customAnchor = /(?<={#).*(?=})/g.exec(titleMdx)?.[0]
80
+ if (customAnchor) {
81
+ headingMdx.anchor = customAnchor
82
+ headingMdx.title = titleMdx.replace(/{#.*}/g, '')
83
+ }
84
+ }
85
+ const headingId = determineSectionUrlHash(headingMdx.anchor)
86
+ const title = headingMdx.title
87
+
88
+ const titleParsed = parseTitle(title)
89
+ assert(headingId === null || headingId.length > 0)
90
+ const headingAttrId = headingId === null ? '' : ` id="${headingId}"`
91
+ const headingHtml = `<h${headingLevel}${headingAttrId}>${titleParsed}</h${headingLevel}>`
92
+
93
+ const heading = { headingLevel, title, headingId, headingHtml }
94
+ return heading
95
+ }
96
+
97
+ function parseTitle(titleMarkdown: string): string {
98
+ type Part = { nodeType: 'text' | 'code'; content: string }
99
+ const parts: Part[] = []
100
+ let current: Part | undefined
101
+ titleMarkdown.split('').forEach((letter) => {
102
+ if (letter === '`') {
103
+ if (current?.nodeType === 'code') {
104
+ // </code>
105
+ parts.push(current)
106
+ current = undefined
107
+ } else {
108
+ // <code>
109
+ if (current) {
110
+ parts.push(current)
111
+ }
112
+ current = { nodeType: 'code', content: '' }
113
+ }
114
+ } else {
115
+ if (!current) {
116
+ current = { nodeType: 'text', content: '' }
117
+ }
118
+ current.content += letter
119
+ }
120
+ })
121
+ if (current) {
122
+ parts.push(current)
123
+ }
124
+
125
+ const titleHtml = parts
126
+ .map((part) => {
127
+ if (part.nodeType === 'code') {
128
+ return `<code>${serializeText(part.content)}</code>`
129
+ } else {
130
+ assert(part.nodeType === 'text', { parts })
131
+ return serializeText(part.content)
132
+ }
133
+ })
134
+ .join('')
135
+
136
+ return titleHtml
137
+
138
+ function serializeText(text: string) {
139
+ let textEscaped = text.split("'").join("\\'")
140
+ // https://github.com/brillout/docpress/pull/2
141
+ if (isWindows()) {
142
+ textEscaped = textEscaped.replace(/\r/, '')
143
+ }
144
+ return `{'${textEscaped}'}`
145
+ }
146
+ }
147
+
148
+ function isWindows() {
149
+ return os.platform() === 'win32'
150
+ }
@@ -0,0 +1,41 @@
1
+ /*
2
+ .nav-item {
3
+ border-top: 1px solid transparent;
4
+ }
5
+ .nav-item.is-active {
6
+ border-color: #eaeaea;
7
+ }
8
+ .nav-item[is-active] {
9
+ background-color: attr(is-active)
10
+ }
11
+ */
12
+
13
+ /*
14
+ #navigation-container:not(:hover) ::-webkit-scrollbar {
15
+ display: none;
16
+ }
17
+ #navigation-container ::-webkit-scrollbar-thumb {
18
+ opacity: 0;
19
+ }
20
+ #navigation-container ::-webkit-scrollbar-track {
21
+ opacity: 0;
22
+ }
23
+ */
24
+
25
+ /*
26
+ .nav-tree:not(.expanded) > .nav-tree {
27
+ edisplay: none;
28
+ background:red;
29
+ }
30
+ */
31
+ /*
32
+ .nav-tree.expanded,
33
+ .nav-tree.expanded > .nav-tree {
34
+ display: inherit;
35
+ }
36
+ .nav-tree.expanded,
37
+ .nav-tree.expanded > .nav-tree {
38
+ display: inherit;
39
+ background:red;
40
+ }
41
+ */
@@ -0,0 +1,119 @@
1
+ .nav-item {
2
+ display: block;
3
+ white-space: nowrap;
4
+ overflow-x: hidden;
5
+ --padding-left-global: 9px;
6
+ --padding-left-additional: 0px;
7
+ }
8
+ .nav-item code {
9
+ font-size: 0.9em;
10
+ }
11
+ .nav-item-h1 + .nav-item-h4 {
12
+ margin-top: -2px;
13
+ }
14
+ .nav-item-h4 {
15
+ margin-top: 14px;
16
+ margin-bottom: -1px;
17
+ color: #999;
18
+ font-size: 12px;
19
+ font-weight: 400;
20
+ letter-spacing: 0.15ch;
21
+ padding-left: var(--padding-left-global);
22
+ padding-right: 4px;
23
+ text-decoration: none;
24
+ }
25
+ .nav-column:first-of-type > .nav-h1-group:first-of-type > .nav-item-h1:first-of-type {
26
+ margin-top: 20px;
27
+ }
28
+ .nav-item-h1 {
29
+ margin-top: 30px;
30
+ font-size: 15.4px;
31
+ text-transform: uppercase;
32
+ font-weight: 600;
33
+ letter-spacing: 0.15ch;
34
+ color: var(--color-text);
35
+ padding: 12px 0;
36
+ padding-left: calc(var(--padding-left-global) - 2px);
37
+ padding-right: 4px;
38
+ text-decoration: none;
39
+ }
40
+ .nav-item-h2 {
41
+ text-decoration: none;
42
+ font-size: 14.4px;
43
+ font-weight: 400;
44
+ letter-spacing: 0.15ch;
45
+ color: var(--color-text);
46
+ padding-left: var(--padding-left-global);
47
+ padding-right: 0;
48
+ --padding: 4px;
49
+ padding-top: var(--padding);
50
+ padding-bottom: var(--padding);
51
+ }
52
+ .nav-item-h3 {
53
+ font-size: 12px;
54
+ font-weight: 400;
55
+ letter-spacing: 0.15ch;
56
+ color: var(--color-text);
57
+ text-decoration: none;
58
+ --padding: 5px;
59
+
60
+ background-color: #f9f9f9;
61
+ padding: var(--padding) 0;
62
+ padding-left: calc(var(--padding-left-global) + var(--padding-left-additional));
63
+ }
64
+ html.navigation-fullscreen .nav-item-h3 {
65
+ border-right: 4px solid #eee;
66
+ }
67
+ .nav-item-h3.nav-item-first-of-its-kind {
68
+ padding-top: calc(var(--padding) * 1.6);
69
+ }
70
+ .nav-item-h3.nav-item-last-of-its-kind {
71
+ padding-bottom: calc(var(--padding) * 2);
72
+ }
73
+ .nav-item-h2,
74
+ .nav-item-h3 {
75
+ position: relative;
76
+ }
77
+ /*
78
+ .nav-item-h2.is-active .nav-item-text{
79
+ background-color: var(--background-color);
80
+ }
81
+ */
82
+ .nav-item-h2.is-active {
83
+ background-color: var(--background-color);
84
+ }
85
+ .nav-item-h3.is-active:before {
86
+ display: block;
87
+ content: '';
88
+ position: absolute;
89
+ width: 4px;
90
+ left: 0;
91
+ top: 0;
92
+ height: 100%;
93
+ background-color: var(--background-color);
94
+ z-index: 10;
95
+ }
96
+ .nav-item-h3.is-active-last:after {
97
+ display: block;
98
+ content: '';
99
+ position: absolute;
100
+ height: 4px;
101
+ left: 0;
102
+ bottom: 0;
103
+ width: 100%;
104
+ background-color: var(--background-color);
105
+ z-index: 10;
106
+ border-bottom-left-radius: 5px;
107
+ }
108
+ html.navigation-fullscreen .nav-item {
109
+ --expend-border-radius: 5px;
110
+ }
111
+ .nav-item.is-active-first {
112
+ border-top-left-radius: 5px;
113
+ border-top-right-radius: var(--expend-border-radius);
114
+ }
115
+ .nav-item.is-active-last,
116
+ .nav-item.is-active-last:before {
117
+ border-bottom-left-radius: 5px;
118
+ border-bottom-right-radius: var(--expend-border-radius);
119
+ }
@@ -0,0 +1,127 @@
1
+ :root {
2
+ --mobile-header-height: 60px;
3
+ --navigation-min-width: 300px;
4
+ --navigation-max-width: 350px;
5
+ }
6
+ #navigation-wrapper {
7
+ min-width: var(--navigation-min-width);
8
+ }
9
+ .doc-page #navigation-wrapper {
10
+ max-width: var(--navigation-max-width);
11
+ }
12
+ .landing-page #navigation-wrapper {
13
+ /* prettier-ignore */
14
+ max-width: min(var(--navigation-max-width), max(var(--navigation-min-width), calc(var(--navigation-min-width) + 100% - 1240px)));
15
+ }
16
+ #navigation-container {
17
+ /* `position: fixed` doesn't inherit the parent's width */
18
+ position: sticky;
19
+ overflow-y: auto;
20
+ overscroll-behavior: contain;
21
+ border-right: 1px solid #eee;
22
+ --background-color: #f0f0f0;
23
+ padding-bottom: 70px;
24
+ }
25
+ .navigation-content {
26
+ margin-top: 20px;
27
+ }
28
+ #navigation-content-detached {
29
+ margin-top: 25px;
30
+ }
31
+
32
+ #navigation-mask {
33
+ position: fixed;
34
+ width: 100%;
35
+ height: 100vh;
36
+ top: 0;
37
+ left: 0;
38
+ z-index: 2;
39
+ }
40
+ /* `1140px` is the breaking point that preserves the width of code blocks. */
41
+ /* BEFORE EDITING THIS: also change the `1139px` value below */
42
+ @media screen and (min-width: 1140px) {
43
+ #mobile-header {
44
+ display: none !important;
45
+ }
46
+ #navigation-container {
47
+ height: 100vh;
48
+ top: 0;
49
+ }
50
+ #navigation-mask {
51
+ display: none;
52
+ }
53
+ }
54
+ #navigation-container {
55
+ transition: transform 0.25s ease;
56
+ background: white;
57
+ z-index: 3;
58
+ }
59
+ #page-wrapper {
60
+ margin-left: calc(-1 * var(--navigation-fullscreen-button-width));
61
+ }
62
+ @media screen and (max-width: 1139px) {
63
+ #navigation-header-logo {
64
+ display: none !important;
65
+ }
66
+ #navigation-wrapper {
67
+ min-width: 0px !important;
68
+ max-width: 0px !important;
69
+ }
70
+ #navigation-fullscreen-button {
71
+ display: none;
72
+ }
73
+ #page-wrapper {
74
+ margin-left: 0 !important;
75
+ }
76
+ #navigation-container {
77
+ --width: min(100%, 350px);
78
+ width: var(--width);
79
+ left: 0;
80
+ height: calc(100vh - var(--mobile-header-height));
81
+ top: var(--mobile-header-height);
82
+ padding-top: 20px;
83
+ /* `position: sticky` doesn't seem to work on mobile */
84
+ position: fixed;
85
+ }
86
+ body:not(.show-menu) #navigation-container {
87
+ transform: translateX(calc(-1 * var(--width)));
88
+ }
89
+ body:not(.show-menu) #navigation-mask {
90
+ display: none;
91
+ }
92
+ #mobile-header {
93
+ display: inherit;
94
+ }
95
+ .doc-page h2 {
96
+ --padding-top: calc(var(--mobile-header-height) + 12px) !important;
97
+ }
98
+ }
99
+
100
+ html.navigation-fullscreen #navigation-container {
101
+ width: 100%;
102
+ height: 100vh;
103
+ position: fixed;
104
+ top: 0;
105
+ left: 0;
106
+ background-color: white;
107
+ }
108
+ html.navigation-fullscreen #navigation-header,
109
+ html.navigation-fullscreen #navigation-content-detached,
110
+ html.navigation-fullscreen #detached-note {
111
+ display: none !important;
112
+ }
113
+ html.navigation-fullscreen .navigation-content {
114
+ display: flex;
115
+ margin: auto; /* A `max-width` is set by src/navigation/navigation-fullscreen/initNavigationFullscreen.ts */
116
+ }
117
+ html.navigation-fullscreen .navigation-content > .nav-column {
118
+ flex-grow: 1;
119
+ max-width: 350px;
120
+ }
121
+ html.navigation-fullscreen .nav-column > .nav-h1-group:first-child > .nav-item-h1:first-child {
122
+ margin-top: 0px;
123
+ }
124
+ html.navigation-fullscreen {
125
+ /* disable scroll of main view */
126
+ overflow: hidden !important;
127
+ }
@@ -0,0 +1,43 @@
1
+ import { initNavigationFullscreen } from './navigation-fullscreen/initNavigationFullscreen'
2
+
3
+ activateNavigationMask()
4
+ activateMenuToggle()
5
+ initNavigationFullscreen()
6
+ autoHideNavigationOverlayOnLinkClick()
7
+ navHeaderRightClickInterceptor()
8
+
9
+ function activateMenuToggle() {
10
+ const menuToggle = document.getElementById('menu-toggle')!
11
+ menuToggle.onclick = navigationOverlayToggle
12
+ }
13
+
14
+ function activateNavigationMask() {
15
+ const navigationMask = document.getElementById('navigation-mask')!
16
+ navigationMask.onclick = navigationOverlayToggle
17
+ }
18
+
19
+ function autoHideNavigationOverlayOnLinkClick() {
20
+ document.addEventListener('click', (ev: any) => {
21
+ const el = ev.target
22
+ if (!el || !('classList' in el)) return
23
+ if (!el.classList.contains('nav-item')) return
24
+ navigationOverlayHide()
25
+ })
26
+ }
27
+
28
+ function navigationOverlayToggle() {
29
+ document.body.classList.toggle('show-menu')
30
+ }
31
+ function navigationOverlayHide() {
32
+ document.body.classList.remove('show-menu')
33
+ }
34
+
35
+ function navHeaderRightClickInterceptor() {
36
+ const navHeader = document.getElementById('navigation-header')!
37
+ if (!navHeader.classList.contains('press-kit')) return
38
+ if (window.location.pathname === '/press') return
39
+ navHeader.oncontextmenu = (ev) => {
40
+ ev.preventDefault()
41
+ window.location.href = '/press'
42
+ }
43
+ }
@@ -0,0 +1,3 @@
1
+ @import './Navigation-layout.css';
2
+ @import './Navigation-items.css';
3
+ @import './Navigation-highlight.css';
@@ -0,0 +1,211 @@
1
+ export { Navigation }
2
+ export { NavigationMask }
3
+
4
+ import React from 'react'
5
+ import { NavigationHeader } from './NavigationHeader'
6
+ import { Heading, HeadingDetached } from '../types/Heading'
7
+ import { assert, Emoji, assertWarning, jsxToTextContent } from '../utils/server'
8
+ import './Navigation.css'
9
+ import { NavigationFullscreenClose } from './navigation-fullscreen/NavigationFullscreenButton'
10
+
11
+ function Navigation({
12
+ pageContext
13
+ }: {
14
+ pageContext: {
15
+ headingsProcessed: Heading[]
16
+ headingsOfDetachedPage: null | (Heading | HeadingDetached)[]
17
+ urlPathname: string
18
+ }
19
+ }) {
20
+ const currentUrl = pageContext.urlPathname
21
+ return (
22
+ <>
23
+ <div id="navigation-container">
24
+ <NavigationHeader />
25
+ {pageContext.headingsOfDetachedPage && (
26
+ <>
27
+ {pageContext.headingsOfDetachedPage.length > 1 && (
28
+ <NavigationContent
29
+ id="navigation-content-detached"
30
+ headingsProcessed={pageContext.headingsOfDetachedPage}
31
+ currentUrl={currentUrl}
32
+ />
33
+ )}
34
+ <DetachedPageNote />
35
+ </>
36
+ )}
37
+ <NavigationContent
38
+ id="navigation-content-main"
39
+ headingsProcessed={pageContext.headingsProcessed}
40
+ currentUrl={currentUrl}
41
+ />
42
+ {/* <ScrollOverlay /> */}
43
+ <NavigationFullscreenClose />
44
+ </div>
45
+ </>
46
+ )
47
+ }
48
+
49
+ function NavigationMask() {
50
+ return <div id="navigation-mask" />
51
+ }
52
+
53
+ function NavigationContent(props: {
54
+ id: 'navigation-content-main' | 'navigation-content-detached'
55
+ headingsProcessed: (Heading | HeadingDetached)[]
56
+ currentUrl: string
57
+ }) {
58
+ const headings = getHeadingsWithComputedProps(props.headingsProcessed, props.currentUrl)
59
+
60
+ const headingsGrouped = groupHeadings(headings)
61
+
62
+ return (
63
+ <div id={props.id} className="navigation-content">
64
+ <div className="nav-column" style={{ position: 'relative' }}>
65
+ {headingsGrouped.map((headingsH1, i) => (
66
+ <div className="nav-h1-group" key={i}>
67
+ <Heading heading={headingsH1} />
68
+ {headingsH1.headings.map((heading, j) => (
69
+ <Heading heading={heading} key={j} />
70
+ ))}
71
+ </div>
72
+ ))}
73
+ </div>
74
+ </div>
75
+ )
76
+ }
77
+
78
+ function Heading({
79
+ heading
80
+ }: {
81
+ heading: {
82
+ level: number
83
+ url?: string | null
84
+ title: string | JSX.Element
85
+ titleInNav: string | JSX.Element
86
+ computed: {
87
+ isActive: boolean
88
+ isActiveFirst: boolean
89
+ isActiveLast: boolean
90
+ isFirstOfItsKind: boolean
91
+ isLastOfItsKind: boolean
92
+ }
93
+ }
94
+ }) {
95
+ assert([1, 2, 3, 4].includes(heading.level), heading)
96
+ if (heading.level === 1 || heading.level === 4) {
97
+ assert(heading.url === undefined)
98
+ } else {
99
+ const sectionTitle = jsxToTextContent(heading.title)
100
+ assertWarning(
101
+ heading.url,
102
+ `${jsxToTextContent(
103
+ heading.titleInNav
104
+ )} is missing a URL hash. Use \`<h2 id="url-hash">${sectionTitle}</h2>\` instead of \`## ${sectionTitle}\`.`
105
+ )
106
+ }
107
+ return (
108
+ <a
109
+ className={[
110
+ 'nav-item',
111
+ 'nav-item-h' + heading.level,
112
+ heading.computed.isActive && ' is-active',
113
+ heading.computed.isActiveFirst && ' is-active-first',
114
+ heading.computed.isActiveLast && ' is-active-last',
115
+ heading.computed.isFirstOfItsKind && 'nav-item-first-of-its-kind',
116
+ heading.computed.isLastOfItsKind && 'nav-item-last-of-its-kind'
117
+ ]
118
+ .filter(Boolean)
119
+ .join(' ')}
120
+ href={heading.url ?? undefined}
121
+ >
122
+ {/* <span className="nav-item-text">{heading.titleInNav}</span> */}
123
+ {heading.titleInNav}
124
+ </a>
125
+ )
126
+ }
127
+
128
+ function groupHeadings<T extends { level: number }>(headings: T[]) {
129
+ const headingsGrouped: (T & { headings: T[] })[] = []
130
+ const headingLevelMin: number = Math.min(...headings.map((h) => h.level))
131
+ headings.forEach((heading) => {
132
+ if (heading.level === headingLevelMin) {
133
+ headingsGrouped.push({ ...heading, headings: [] })
134
+ } else {
135
+ headingsGrouped[headingsGrouped.length - 1].headings.push(heading)
136
+ }
137
+ })
138
+ return headingsGrouped
139
+ }
140
+
141
+ function getHeadingsWithComputedProps(headings: (Heading | HeadingDetached)[], currentUrl: string) {
142
+ return headings.map((heading, i) => {
143
+ assert([1, 2, 3, 4].includes(heading.level), heading)
144
+
145
+ const headingPrevious = headings[i - 1]
146
+ const headingNext = headings[i + 1]
147
+
148
+ let isActiveFirst = false
149
+ let isActiveLast = false
150
+ let isActive = false
151
+ if (heading.url === currentUrl) {
152
+ assert(heading.level === 2, { currentUrl })
153
+ isActive = true
154
+ isActiveFirst = true
155
+ if (headingNext?.level !== 3) {
156
+ isActiveLast = true
157
+ }
158
+ }
159
+ if (heading.level === 3) {
160
+ isActive = true
161
+ if (headingNext?.level !== 3) {
162
+ isActiveLast = true
163
+ }
164
+ }
165
+
166
+ const isFirstOfItsKind = heading.level !== headingPrevious?.level
167
+ const isLastOfItsKind = heading.level !== headingNext?.level
168
+
169
+ return {
170
+ ...heading,
171
+ computed: {
172
+ isActive,
173
+ isActiveFirst,
174
+ isActiveLast,
175
+ isFirstOfItsKind,
176
+ isLastOfItsKind
177
+ }
178
+ }
179
+ })
180
+ }
181
+
182
+ function DetachedPageNote() {
183
+ return (
184
+ <div
185
+ id="detached-note"
186
+ style={{
187
+ backgroundColor: 'var(--background-color)',
188
+ textAlign: 'left',
189
+ marginLeft: 10,
190
+ marginRight: 10,
191
+ marginTop: 25,
192
+ marginBottom: -5,
193
+ borderRadius: 5,
194
+ padding: 10
195
+ }}
196
+ >
197
+ <Emoji name="info" />{' '}
198
+ <b>
199
+ <em>Detached</em>
200
+ </b>
201
+ <span
202
+ style={{
203
+ opacity: 0.8
204
+ }}
205
+ >
206
+ {' '}
207
+ &mdash; this page isn't listed in the navigation below.
208
+ </span>
209
+ </div>
210
+ )
211
+ }