@brillout/docpress 0.5.40 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/+config.ts +17 -0
  2. package/MobileHeader.tsx +68 -0
  3. package/PageLayout.css +42 -0
  4. package/PageLayout.tsx +39 -0
  5. package/algolia/DocSearch.css +34 -0
  6. package/algolia/DocSearch.ts +62 -0
  7. package/autoScrollNav.ts +36 -0
  8. package/components/CodeBlockTransformer.css +9 -0
  9. package/components/CodeBlockTransformer.tsx +18 -0
  10. package/components/Comment.tsx +7 -0
  11. package/components/Consulting.tsx +47 -0
  12. package/components/Contributors.tsx +113 -0
  13. package/components/EditPageNote.tsx +18 -0
  14. package/components/FeatureList/FeatureList.client.ts +66 -0
  15. package/{dist/components/features → components/FeatureList}/FeatureList.css +10 -2
  16. package/components/FeatureList/FeatureList.tsx +114 -0
  17. package/components/HorizontalLine.tsx +20 -0
  18. package/components/ImportMeta.tsx +11 -0
  19. package/components/Link.tsx +144 -0
  20. package/components/Note.css +54 -0
  21. package/components/Note.tsx +78 -0
  22. package/components/P.css +8 -0
  23. package/components/P.tsx +8 -0
  24. package/components/ReadingRecommendation.tsx +56 -0
  25. package/components/RepoLink.tsx +24 -0
  26. package/components/Sponsors/label.draft.svg +108 -0
  27. package/components/Sponsors.tsx +218 -0
  28. package/components/Supporters.tsx +136 -0
  29. package/components/index.ts +14 -0
  30. package/config/getConfig.ts +18 -0
  31. package/config/resolveConfig/resolveHeading.ts +0 -0
  32. package/config/resolvePageContext.ts +186 -0
  33. package/css/button.css +7 -0
  34. package/css/code/block.css +36 -0
  35. package/css/code/inline.css +27 -0
  36. package/css/code.css +20 -0
  37. package/css/colorize-on-hover.css +29 -0
  38. package/css/font.css +25 -0
  39. package/css/heading.css +45 -0
  40. package/css/index.css +12 -0
  41. package/css/link.css +17 -0
  42. package/css/reset.css +12 -0
  43. package/css/table.css +14 -0
  44. package/css/tooltip.css +11 -0
  45. package/data/maintainersList.tsx +92 -0
  46. package/data/sponsorsList.ts +147 -0
  47. package/dist/+config.d.ts +19 -0
  48. package/dist/+config.js +15 -0
  49. package/dist/markdownHeadingsVitePlugin.d.ts +13 -0
  50. package/dist/markdownHeadingsVitePlugin.js +170 -0
  51. package/dist/utils/assert.d.ts +6 -0
  52. package/dist/utils/assert.js +48 -0
  53. package/dist/utils/determineSectionUrlHash.d.ts +4 -0
  54. package/dist/utils/determineSectionUrlHash.js +38 -0
  55. package/dist/vite.config.d.ts +3 -0
  56. package/dist/vite.config.js +32 -0
  57. package/index.ts +4 -0
  58. package/installSectionUrlHashs.ts +60 -0
  59. package/markdownHeadingsVitePlugin.ts +150 -0
  60. package/navigation/Navigation-highlight.css +41 -0
  61. package/navigation/Navigation-items.css +119 -0
  62. package/navigation/Navigation-layout.css +127 -0
  63. package/navigation/Navigation.client.ts +43 -0
  64. package/navigation/Navigation.css +3 -0
  65. package/navigation/Navigation.tsx +211 -0
  66. package/navigation/NavigationHeader.tsx +111 -0
  67. package/navigation/navigation-fullscreen/NavigationFullscreenButton.css +32 -0
  68. package/navigation/navigation-fullscreen/NavigationFullscreenButton.tsx +44 -0
  69. package/navigation/navigation-fullscreen/initNavigationFullscreen.ts +116 -0
  70. package/package.json +38 -53
  71. package/parseEmojis.ts +35 -0
  72. package/parseTitle.ts +139 -0
  73. package/renderer/client.ts +4 -0
  74. package/renderer/onRenderHtml.tsx +69 -0
  75. package/renderer/usePageContext.tsx +25 -0
  76. package/tsconfig.config.json +7 -0
  77. package/tsconfig.json +15 -0
  78. package/types/Config.ts +46 -0
  79. package/types/Heading.ts +49 -0
  80. package/utils/Emoji/Emoji.ts +224 -0
  81. package/utils/Emoji/assets.ts +9 -0
  82. package/utils/Emoji/index.ts +1 -0
  83. package/utils/Emoji/mountain.svg +1 -0
  84. package/utils/assert.ts +51 -0
  85. package/utils/client.ts +2 -0
  86. package/utils/determineSectionUrlHash.ts +44 -0
  87. package/utils/filesystemPathHandling.ts +42 -0
  88. package/utils/filter.ts +12 -0
  89. package/utils/isBrowser.ts +5 -0
  90. package/utils/jsxToTextContent.ts +11 -0
  91. package/utils/objectAssign.ts +9 -0
  92. package/utils/server.ts +7 -0
  93. package/vite.config.ts +36 -0
  94. package/bin.js +0 -3
  95. package/dist/chunk-2ZTPUQGS.js +0 -58
  96. package/dist/chunk-3QC7HYIF.js +0 -7
  97. package/dist/chunk-MGOI4AFO.js +0 -165
  98. package/dist/chunk-NVJING6T.js +0 -91
  99. package/dist/chunk-QWL3MA4E.js +0 -171
  100. package/dist/chunk-UN23G34B.js +0 -157
  101. package/dist/cli/index.d.ts +0 -1
  102. package/dist/cli/index.js +0 -34
  103. package/dist/components/features/FeatureList.d.ts +0 -13
  104. package/dist/components/features/FeatureList.js +0 -7
  105. package/dist/components/features/initFeatureList.d.ts +0 -3
  106. package/dist/components/features/initFeatureList.js +0 -59
  107. package/dist/devServer-JKH6U5PF.js +0 -36
  108. package/dist/index.css +0 -120
  109. package/dist/index.d.ts +0 -221
  110. package/dist/index.js +0 -947
  111. package/dist/renderer/_default.page.client.css +0 -318
  112. package/dist/renderer/_default.page.client.d.ts +0 -1
  113. package/dist/renderer/_default.page.client.js +0 -218
  114. package/dist/renderer/_default.page.server.css +0 -310
  115. package/dist/renderer/_default.page.server.d.ts +0 -22
  116. package/dist/renderer/_default.page.server.js +0 -665
  117. package/readme.md +0 -5
  118. /package/{dist/chevron-R2IYJD62.svg → components/FeatureList/chevron.svg} +0 -0
  119. /package/{dist/label-MP75CTIA.svg → components/Sponsors/label.svg} +0 -0
  120. /package/{dist/medalBronze-CO4CTUR4.svg → components/Sponsors/medalBronze.svg} +0 -0
  121. /package/{dist/medalGold-UP6A73FL.svg → components/Sponsors/medalGold.svg} +0 -0
  122. /package/{dist/medalSilver-FAPGGOBN.svg → components/Sponsors/medalSilver.svg} +0 -0
  123. /package/{dist/Inter-Var-IOAEQULN.ttf → css/Inter-Var.ttf} +0 -0
  124. /package/{dist/alignable-B4QZV4X7.svg → data/sponsorsList/companyLogos/alignable.svg} +0 -0
  125. /package/{dist/bluefin-JQABZFGV.svg → data/sponsorsList/companyLogos/bluefin.svg} +0 -0
  126. /package/{dist/burdaforward-EUGURYZY.png → data/sponsorsList/companyLogos/burdaforward.png} +0 -0
  127. /package/{dist/contra-WLZBOPBV.svg → data/sponsorsList/companyLogos/contra.svg} +0 -0
  128. /package/{dist/ecosia-OYRLTR5T.svg → data/sponsorsList/companyLogos/ecosia.svg} +0 -0
  129. /package/{dist/inlang-GFRWND6X.png → data/sponsorsList/companyLogos/inlang.png} +0 -0
  130. /package/{dist/optimizers-SFEZF3NW.svg → data/sponsorsList/companyLogos/optimizers.svg} +0 -0
  131. /package/{dist/sourcegraph-YR2HADLS.svg → data/sponsorsList/companyLogos/sourcegraph.svg} +0 -0
  132. /package/{dist/changelog-IPI5F42D.svg → icons/changelog.svg} +0 -0
  133. /package/{dist/discord-JD33TUSF.svg → icons/discord.svg} +0 -0
  134. /package/{dist/github-P5ZSKN2N.svg → icons/github.svg} +0 -0
  135. /package/{dist/heart-OINVKOXO.svg → icons/heart.svg} +0 -0
  136. /package/{dist/languages-KXPKJFQL.svg → icons/languages.svg} +0 -0
  137. /package/{dist/people-72KKQHU4.svg → icons/people.svg} +0 -0
  138. /package/{dist/twitter-I7DXDN3J.svg → icons/twitter.svg} +0 -0
  139. /package/{dist/chevron-K3WPYLOP.svg → navigation/navigation-fullscreen/chevron.svg} +0 -0
  140. /package/{dist/close-IQXTDOHV.svg → navigation/navigation-fullscreen/close.svg} +0 -0
  141. /package/{dist/compass-2RWQU3E4.svg → utils/Emoji/compass.svg} +0 -0
  142. /package/{dist/engine-6Q6VSCVA.png → utils/Emoji/engine.png} +0 -0
  143. /package/{dist/mechanical-arm-TR7IQQMG.svg → utils/Emoji/mechanical-arm.svg} +0 -0
  144. /package/{dist/road-fork-3WZLW3HB.svg → utils/Emoji/road-fork.svg} +0 -0
  145. /package/{dist/shield-CU45RG5C.svg → utils/Emoji/shield.svg} +0 -0
  146. /package/{dist/typescript-ALIPKLRM.svg → utils/Emoji/typescript.svg} +0 -0
@@ -0,0 +1,218 @@
1
+ export { Sponsors }
2
+ export type { Sponsor }
3
+
4
+ import React from 'react'
5
+ import iconHeart from '../icons/heart.svg'
6
+ import { usePageContext } from '../renderer/usePageContext'
7
+ import { assert, Emoji } from '../utils/server'
8
+ import { Supporter, SupporterSection, SectionDescription, Individuals, SupporterImg, CallToAction } from './Supporters'
9
+ import medalGold from './Sponsors/medalGold.svg'
10
+ import medalSilver from './Sponsors/medalSilver.svg'
11
+ import medalBronze from './Sponsors/medalBronze.svg'
12
+ import labelBgImg from './Sponsors/label.svg'
13
+ import { sponsorsList } from '../data/sponsorsList'
14
+
15
+ type Plan = 'indie' | 'bronze' | 'silver' | 'gold' | 'platinum'
16
+
17
+ type SponsorCompany = {
18
+ companyName: string
19
+ companyLogo: string
20
+ website: string
21
+ plan: Plan
22
+ divSize?: Partial<DivSize>
23
+ github: string
24
+ }
25
+ type SponsorIndividual = {
26
+ username: string
27
+ }
28
+ type Sponsor = SponsorCompany | SponsorIndividual
29
+
30
+ type DivSize = {
31
+ width: number
32
+ height: number
33
+ padding: number
34
+ }
35
+
36
+ function Sponsors() {
37
+ const pageContext = usePageContext()
38
+ const { projectInfo } = pageContext.config
39
+ const sponsorGithubAccount = pageContext.config.sponsorGithubAccount || 'brillout'
40
+ const sponsorsCompanies = sponsorsList.filter(isCompany)
41
+ const sponsorsIndividuals = sponsorsList.filter(isIndividual)
42
+ return (
43
+ <SupporterSection>
44
+ <CallToAction iconUrl={iconHeart} text="Sponsor" href={`https://github.com/sponsors/${sponsorGithubAccount}`} />
45
+ <div></div>
46
+ <SectionDescription>
47
+ {projectInfo.projectName} is free and open source, made possible by wonderful sponsors.
48
+ </SectionDescription>
49
+ <div style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'space-evenly', alignItems: 'end' }}>
50
+ {sponsorsCompanies.map((sponsor, i) => (
51
+ <SponsorDiv sponsor={sponsor} key={i} />
52
+ ))}
53
+ </div>
54
+ <Individuals>
55
+ {sponsorsIndividuals.map((sponsor, i) => (
56
+ <SponsorDiv sponsor={sponsor} key={i} />
57
+ ))}
58
+ </Individuals>
59
+ </SupporterSection>
60
+ )
61
+ }
62
+
63
+ function SponsorDiv({ sponsor }: { sponsor: Sponsor }) {
64
+ if (isIndividual(sponsor)) {
65
+ return <Supporter username={sponsor.username} />
66
+ }
67
+ return <CompanyDiv sponsor={sponsor} />
68
+ }
69
+
70
+ function CompanyDiv({ sponsor }: { sponsor: Sponsor }) {
71
+ assert(isCompany(sponsor))
72
+ const imgSrc = sponsor.companyLogo
73
+ const imgAlt = sponsor.companyName
74
+ const { width, height, padding } = getSize(sponsor)
75
+ const marginHeight = 20
76
+ const marginWidth = 10
77
+ return (
78
+ <a
79
+ href={sponsor.website}
80
+ style={{
81
+ margin: `${marginHeight}px ${marginWidth}px`
82
+ }}
83
+ >
84
+ <Label sponsor={sponsor} />
85
+ <div
86
+ style={{
87
+ backgroundColor: '#f0f0f0',
88
+ borderRadius: 7,
89
+ overflow: 'hidden',
90
+ width,
91
+ maxWidth: `calc(100vw - 2 * var(--main-view-padding) - 2 * ${marginWidth}px)`,
92
+ height,
93
+ display: 'flex',
94
+ alignItems: 'center',
95
+ flexDirection: 'column',
96
+ justifyContent: 'center'
97
+ }}
98
+ >
99
+ <SupporterImg {...{ imgSrc, imgAlt, width, height, padding }} />
100
+ </div>
101
+ </a>
102
+ )
103
+ }
104
+
105
+ function Label({ sponsor }: { sponsor: Sponsor }) {
106
+ assert(isCompany(sponsor))
107
+ const labelBg = getLabelBg(sponsor)
108
+ const labelIcon = getLabelIcon(sponsor)
109
+ const labelText = getLabelText(sponsor)
110
+ return (
111
+ <div
112
+ style={{
113
+ top: 0,
114
+ display: 'flex',
115
+ justifyContent: 'center',
116
+ alignItems: 'center',
117
+ position: 'relative',
118
+ paddingBottom: 1
119
+ }}
120
+ >
121
+ {labelBg}
122
+ {labelIcon}
123
+ {labelText}
124
+ </div>
125
+ )
126
+ }
127
+
128
+ function getLabelBg(sponsor: SponsorCompany) {
129
+ const height = sponsor.plan === 'platinum' ? 32 : 24
130
+ return <img src={labelBgImg} style={{ height, position: 'absolute', bottom: 0, zIndex: -1 }} />
131
+ }
132
+
133
+ function getLabelText(sponsor: SponsorCompany) {
134
+ if (sponsor.plan === 'platinum') {
135
+ return <></>
136
+ }
137
+ let letterSpacing: number | undefined = undefined
138
+ if (['bronze', 'silver', 'gold', 'indie'].includes(sponsor.plan)) {
139
+ letterSpacing = 1
140
+ }
141
+ /*
142
+ if (sponsor.plan === 'indie') {
143
+ letterSpacing = 2
144
+ }
145
+ */
146
+ return (
147
+ <>
148
+ {' '}
149
+ <span
150
+ style={{
151
+ zIndex: 1,
152
+ fontSize: '0.82em',
153
+ position: 'relative',
154
+ top: 0,
155
+ fontWeight: 500,
156
+ color: '#666',
157
+ letterSpacing
158
+ }}
159
+ >
160
+ {capitalizeFirstLetter(sponsor.plan)}
161
+ </span>
162
+ </>
163
+ )
164
+ }
165
+
166
+ function getLabelIcon(sponsor: SponsorCompany) {
167
+ let medalSrc: string
168
+ if (sponsor.plan === 'platinum') {
169
+ return <Emoji name="trophy" style={{ fontSize: '1.3em' }} />
170
+ } else if (sponsor.plan === 'indie') {
171
+ return <Emoji name="ribbon" style={{ fontSize: '0.9em' /*, position: 'relative', top: -1*/ }} />
172
+ } else if (sponsor.plan === 'gold') {
173
+ medalSrc = medalGold
174
+ } else if (sponsor.plan === 'silver') {
175
+ medalSrc = medalSilver
176
+ } else if (sponsor.plan === 'bronze') {
177
+ medalSrc = medalBronze
178
+ } else {
179
+ assert(false)
180
+ }
181
+ return <img src={medalSrc} style={{ height: 15, zIndex: 1, marginRight: 5 }} />
182
+ }
183
+
184
+ function getSize(sponsor: SponsorCompany): DivSize {
185
+ const { plan } = sponsor
186
+ let divSize: DivSize | undefined
187
+ if (plan === 'platinum') {
188
+ divSize = { width: 500, height: 180, padding: 100 }
189
+ }
190
+ if (plan === 'gold') {
191
+ divSize = { width: 400, height: 150, padding: 95 }
192
+ }
193
+ if (plan === 'silver') {
194
+ divSize = { width: 300, height: 100, padding: 45 }
195
+ }
196
+ if (plan === 'bronze') {
197
+ divSize = { width: 200, height: 70, padding: 30 }
198
+ }
199
+ if (plan === 'indie') {
200
+ divSize = { width: 140, height: 50, padding: 20 }
201
+ }
202
+ assert(divSize)
203
+ if (sponsor.divSize) {
204
+ Object.assign(divSize, sponsor.divSize)
205
+ }
206
+ return divSize
207
+ }
208
+
209
+ function capitalizeFirstLetter(word: string): string {
210
+ return word[0].toUpperCase() + word.slice(1)
211
+ }
212
+
213
+ function isCompany(sponsor: Sponsor): sponsor is SponsorCompany {
214
+ return !isIndividual(sponsor)
215
+ }
216
+ function isIndividual(sponsor: Sponsor): sponsor is SponsorIndividual {
217
+ return 'username' in sponsor
218
+ }
@@ -0,0 +1,136 @@
1
+ // supporters = sponsors + contributors
2
+
3
+ export { Supporter, SupporterSection, SectionDescription, Individuals, SupporterImg, CallToAction }
4
+
5
+ import React from 'react'
6
+
7
+ type Children = (string | JSX.Element) | (string | JSX.Element)[]
8
+
9
+ function SupporterSection({ children }: { children?: Children }) {
10
+ return (
11
+ <div
12
+ style={{
13
+ textAlign: 'center',
14
+ marginTop: 19
15
+ }}
16
+ >
17
+ {children}
18
+ </div>
19
+ )
20
+ }
21
+
22
+ function SectionDescription({ children }: { children?: Children }) {
23
+ return (
24
+ <div
25
+ style={{
26
+ maxWidth: 400,
27
+ display: 'inline-block',
28
+ marginTop: 12,
29
+ marginBottom: 12
30
+ }}
31
+ >
32
+ {children}
33
+ </div>
34
+ )
35
+ }
36
+
37
+ function Individuals({ children }: { children?: Children }) {
38
+ return (
39
+ <div
40
+ style={{
41
+ display: 'flex',
42
+ flexWrap: 'wrap',
43
+ justifyContent: 'center',
44
+ alignItems: 'end',
45
+ margin: '17px auto',
46
+ maxWidth: 700
47
+ }}
48
+ >
49
+ {children}
50
+ </div>
51
+ )
52
+ }
53
+
54
+ // Individual sponsor or small contributor
55
+ function Supporter({ username, avatarUrl }: { username: string; avatarUrl?: string }) {
56
+ const website = `https://github.com/${username}`
57
+ const width = 30
58
+ const height = 30
59
+ const marginWidth = 5
60
+ const marginHeight = 5
61
+ return (
62
+ <a
63
+ href={website}
64
+ style={{
65
+ margin: `${marginHeight}px ${marginWidth}px`
66
+ }}
67
+ >
68
+ <div
69
+ style={{
70
+ borderRadius: 7,
71
+ overflow: 'hidden',
72
+ width,
73
+ height,
74
+ display: 'flex',
75
+ alignItems: 'center',
76
+ flexDirection: 'column',
77
+ justifyContent: 'center'
78
+ }}
79
+ >
80
+ <SupporterImg {...{ username, avatarUrl, width, height }} />
81
+ </div>
82
+ </a>
83
+ )
84
+ }
85
+
86
+ function SupporterImg({
87
+ imgSrc, // has precedence over avatarUrl
88
+ avatarUrl, // has precedence over username
89
+ username,
90
+ imgAlt,
91
+ width,
92
+ height,
93
+ padding = 0
94
+ }: {
95
+ imgSrc?: string
96
+ avatarUrl?: string
97
+ username?: string
98
+ imgAlt?: string
99
+ width: number
100
+ height: number
101
+ padding?: number
102
+ }) {
103
+ const size = Math.max(width, height)
104
+ if (avatarUrl) {
105
+ imgSrc = imgSrc || `${avatarUrl}&size=${size}`
106
+ }
107
+ if (username) {
108
+ imgSrc = imgSrc || `https://github.com/${username}.png?size=${size}`
109
+ imgAlt = imgAlt || username
110
+ }
111
+ return (
112
+ <img
113
+ style={{ width: `calc(100% - ${padding}px)`, height: height - padding, zIndex: 2, objectFit: 'contain' }}
114
+ src={imgSrc}
115
+ alt={imgAlt}
116
+ />
117
+ )
118
+ }
119
+
120
+ function CallToAction({ iconUrl, text, href }: { iconUrl: string; text: string; href: string }) {
121
+ return (
122
+ <a
123
+ className="button"
124
+ style={{
125
+ color: 'inherit',
126
+ display: 'inline-flex',
127
+ alignItems: 'center',
128
+ padding: '5px 10px',
129
+ marginBottom: 10
130
+ }}
131
+ href={href}
132
+ >
133
+ <img src={iconUrl} height={22} /> <span style={{ marginLeft: 7, fontSize: '1.07em' }}>{text}</span>
134
+ </a>
135
+ )
136
+ }
@@ -0,0 +1,14 @@
1
+ export * from '../utils/Emoji'
2
+ export * from './Link'
3
+ export * from './RepoLink'
4
+ export * from './P'
5
+ export * from './ReadingRecommendation'
6
+ export * from './Note'
7
+ export * from './ImportMeta'
8
+ export * from './HorizontalLine'
9
+ export * from './Supporters'
10
+ export * from './Sponsors'
11
+ export * from './Contributors'
12
+ export * from './Consulting'
13
+ export * from './CodeBlockTransformer'
14
+ export * from './Comment'
@@ -0,0 +1,18 @@
1
+ export { getConfig }
2
+ import { assert, assertUsage } from '../utils/server'
3
+ import { Config } from '../types/Config'
4
+
5
+ function getConfig(): Config {
6
+ // We use `@ts-ignore` because the DocPress user most likely didn't add `vite/client` in his `tsconfig.json`.
7
+ // @ts-ignore
8
+ const globResult = import.meta.glob('/**/docpress.config.*([a-zA-Z0-9])', { eager: true })
9
+ const files = Object.keys(globResult)
10
+ assertUsage(files.length >= 1, 'No DocPress config file found `docpress.config.(js|ts|tsx|...)`')
11
+ assertUsage(
12
+ files.length === 1,
13
+ `Found multiple \`docpress.config.js\` files: ${files.map((f) => `\`${f}\``).join(', ')}. Define only one instead.`
14
+ )
15
+ const config = (Object.values(globResult)[0] as any).default as Config
16
+ assert(config)
17
+ return config
18
+ }
File without changes
@@ -0,0 +1,186 @@
1
+ import { assert, jsxToTextContent, objectAssign } from '../utils/server'
2
+ import type { Heading, HeadingDetached } from '../types/Heading'
3
+ import type { PageContextBuiltInServer } from 'vike/types'
4
+ import type { MarkdownHeading } from '../markdownHeadingsVitePlugin'
5
+ import type { Config } from '../types/Config'
6
+ import { getConfig } from './getConfig'
7
+ import { getHeadingsWithProcessedTitle, parseTitle } from '../parseTitle'
8
+
9
+ export { resolvePageContext }
10
+ export type { PageContextOriginal }
11
+ export type { PageContextResolved }
12
+ export type { Heading }
13
+
14
+ type ReactComponent = () => JSX.Element
15
+ type Exports = {
16
+ headings?: MarkdownHeading[]
17
+ }
18
+ type PageContextOriginal = PageContextBuiltInServer & {
19
+ Page: ReactComponent
20
+ exports: Exports
21
+ }
22
+ type PageContextResolved = ReturnType<typeof resolvePageContext>
23
+
24
+ function resolvePageContext(pageContext: PageContextOriginal) {
25
+ const config = getConfig()
26
+ const processed = getHeadingsWithProcessedTitle(config)
27
+ const { headingsDetachedProcessed } = processed
28
+ let { headingsProcessed } = processed
29
+ const { activeHeading, activeNavigationHeading } = findHeading(
30
+ headingsProcessed,
31
+ headingsDetachedProcessed,
32
+ pageContext
33
+ )
34
+ let headingsOfDetachedPage: null | (Heading | HeadingDetached)[] = null
35
+ let headingsAll = [...headingsProcessed, ...headingsDetachedProcessed]
36
+ headingsAll = getHeadingsAll(headingsAll, pageContext, activeHeading)
37
+ if (activeNavigationHeading) {
38
+ headingsProcessed = getHeadingsAll(headingsProcessed, pageContext, activeNavigationHeading)
39
+ } else {
40
+ headingsOfDetachedPage = [activeHeading, ...getHeadingsOfTheCurrentPage(pageContext, activeHeading)]
41
+ }
42
+ const { title, isLandingPage, pageTitle } = getMetaData(
43
+ headingsDetachedProcessed,
44
+ activeNavigationHeading,
45
+ pageContext,
46
+ config
47
+ )
48
+ const { faviconUrl, algolia, tagline, twitterHandle, bannerUrl, websiteUrl } = config
49
+ const pageContextResolved = {}
50
+ objectAssign(pageContextResolved, {
51
+ ...pageContext,
52
+ meta: {
53
+ title,
54
+ faviconUrl,
55
+ twitterHandle,
56
+ bannerUrl,
57
+ websiteUrl,
58
+ tagline,
59
+ algolia
60
+ },
61
+ activeHeading,
62
+ headingsAll,
63
+ headingsProcessed,
64
+ headingsDetachedProcessed,
65
+ headingsOfDetachedPage,
66
+ isLandingPage,
67
+ pageTitle,
68
+ config
69
+ })
70
+ return pageContextResolved
71
+ }
72
+
73
+ function getMetaData(
74
+ headingsDetachedProcessed: HeadingDetached[],
75
+ activeNavigationHeading: Heading | null,
76
+ pageContext: { urlOriginal: string; exports: Exports },
77
+ config: Config
78
+ ) {
79
+ const url = pageContext.urlOriginal
80
+
81
+ let title: string
82
+ let pageTitle: string | JSX.Element | null
83
+ if (activeNavigationHeading) {
84
+ title = activeNavigationHeading.titleDocument || jsxToTextContent(activeNavigationHeading.title)
85
+ pageTitle = activeNavigationHeading.title
86
+ } else {
87
+ pageTitle = headingsDetachedProcessed.find((h) => h.url === url)!.title
88
+ title = jsxToTextContent(pageTitle)
89
+ }
90
+
91
+ const isLandingPage = url === '/'
92
+ if (!isLandingPage) {
93
+ title += ' | ' + config.projectInfo.projectName
94
+ }
95
+
96
+ if (isLandingPage) {
97
+ pageTitle = null
98
+ }
99
+
100
+ return { title, isLandingPage, pageTitle }
101
+ }
102
+
103
+ function findHeading(
104
+ headingsProcessed: Heading[],
105
+ headingsDetachedProcessed: HeadingDetached[],
106
+ pageContext: { urlOriginal: string; exports: Exports }
107
+ ): { activeHeading: Heading | HeadingDetached; activeNavigationHeading: Heading | null } {
108
+ let activeNavigationHeading: Heading | null = null
109
+ let activeHeading: Heading | HeadingDetached | null = null
110
+ assert(pageContext.urlOriginal)
111
+ const pageUrl = pageContext.urlOriginal
112
+ headingsProcessed.forEach((heading) => {
113
+ if (heading.url === pageUrl) {
114
+ activeNavigationHeading = heading
115
+ activeHeading = heading
116
+ assert(heading.level === 2, { pageUrl, heading })
117
+ }
118
+ })
119
+ if (!activeHeading) {
120
+ activeHeading = headingsDetachedProcessed.find(({ url }) => pageUrl === url) ?? null
121
+ }
122
+ if (!activeHeading) {
123
+ throw new Error(
124
+ [
125
+ `Heading not found for URL '${pageUrl}'`,
126
+ 'Heading is defined for following URLs:',
127
+ ...headingsProcessed
128
+ .map((h) => ` ${h.url}`)
129
+ .filter(Boolean)
130
+ .sort()
131
+ ].join('\n')
132
+ )
133
+ }
134
+ return { activeHeading, activeNavigationHeading }
135
+ }
136
+
137
+ function getHeadingsAll<T extends Heading | HeadingDetached>(
138
+ headingsProcessed: T[],
139
+ pageContext: { exports: Exports; urlOriginal: string },
140
+ activeHeading: T
141
+ ): T[] {
142
+ const headingsAll = headingsProcessed.slice()
143
+
144
+ const headingsOfTheCurrentPage = getHeadingsOfTheCurrentPage(pageContext, activeHeading)
145
+
146
+ const activeHeadingIdx = headingsAll.indexOf(activeHeading)
147
+ assert(activeHeadingIdx >= 0)
148
+ headingsOfTheCurrentPage.forEach((pageHeading, i) => {
149
+ headingsAll.splice(activeHeadingIdx + 1 + i, 0, pageHeading as T)
150
+ })
151
+
152
+ return headingsAll
153
+ }
154
+
155
+ function getHeadingsOfTheCurrentPage(
156
+ pageContext: { exports: Exports; urlOriginal: string },
157
+ currentHeading: Heading | HeadingDetached
158
+ ) {
159
+ const headingsOfCurrentPage: Heading[] = []
160
+
161
+ const headingsExport = pageContext.exports.headings ?? []
162
+
163
+ headingsExport.forEach((markdownHeading) => {
164
+ const title = parseTitle(markdownHeading.title)
165
+ const url: null | string = markdownHeading.headingId && '#' + markdownHeading.headingId
166
+ if (markdownHeading.headingLevel === 2) {
167
+ const heading: Heading = {
168
+ url,
169
+ title,
170
+ headingsBreadcrumb: [currentHeading, ...(currentHeading.headingsBreadcrumb ?? [])],
171
+ titleInNav: title,
172
+ level: 3
173
+ }
174
+ headingsOfCurrentPage.push(heading)
175
+ }
176
+ })
177
+
178
+ if (currentHeading?.sectionTitles) {
179
+ currentHeading.sectionTitles.forEach((sectionTitle) => {
180
+ const pageHeadingTitles = headingsExport.map((h) => h.title)
181
+ assert(pageHeadingTitles.includes(sectionTitle), { pageHeadingTitles, sectionTitle })
182
+ })
183
+ }
184
+
185
+ return headingsOfCurrentPage
186
+ }
package/css/button.css ADDED
@@ -0,0 +1,7 @@
1
+ button,
2
+ a.button {
3
+ background-color: #fafafa;
4
+ border: 1px solid #aaa;
5
+ border-radius: 5px;
6
+ cursor: pointer;
7
+ }
@@ -0,0 +1,36 @@
1
+ pre > code {
2
+ padding: 16px !important;
3
+ }
4
+ @media screen and (max-width: 900px) {
5
+ pre > code {
6
+ font-size: 0.7em;
7
+ }
8
+ }
9
+ pre {
10
+ display: grid;
11
+ }
12
+ pre > code {
13
+ padding-right: 0px !important;
14
+ overflow-x: auto;
15
+ }
16
+
17
+ @media screen and (max-width: 1139px) {
18
+ pre > code {
19
+ font-size: 0.95em;
20
+ }
21
+ }
22
+ @media screen and (max-width: 1040px) {
23
+ pre > code {
24
+ font-size: 0.8em;
25
+ }
26
+ }
27
+ @media screen and (max-width: 940px) {
28
+ pre > code {
29
+ font-size: 0.7em;
30
+ }
31
+ }
32
+
33
+ pre > code {
34
+ display: reset;
35
+ word-break: reset;
36
+ }
@@ -0,0 +1,27 @@
1
+ code {
2
+ padding: 2px 5px;
3
+ }
4
+
5
+ /*
6
+ * Line breaks in `<code>`:
7
+ * - Avoid them on desktop
8
+ * - Allow them on mobile
9
+ * - Allo them for `<code long>`
10
+ */
11
+ code {
12
+ display: inline-block;
13
+ }
14
+ @media screen and (max-width: 500px) {
15
+ code {
16
+ word-break: break-word;
17
+ display: inline;
18
+ }
19
+ }
20
+ .inline-code-break code {
21
+ display: inline;
22
+ word-break: break-word;
23
+ }
24
+ code.long {
25
+ word-break: break-word;
26
+ display: inline;
27
+ }
package/css/code.css ADDED
@@ -0,0 +1,20 @@
1
+ @import './code/inline.css';
2
+ @import './code/block.css';
3
+
4
+ code {
5
+ /*
6
+ background-color: #f4f4f4;
7
+ 0.043137255 = 1 - (#f4 / #ff)
8
+ */
9
+ background-color: rgba(0, 0, 0, 0.043137255);
10
+ border-radius: 4px;
11
+ }
12
+
13
+ /* Inline */
14
+ code {
15
+ font-size: 1.1em;
16
+ }
17
+ /* Block */
18
+ pre > code {
19
+ font-size: 1em;
20
+ }
@@ -0,0 +1,29 @@
1
+ .colorize-on-hover,
2
+ .colorize-on-hover [class^='decolorize-'],
3
+ .colorize-on-hover [class*=' decolorize-'] {
4
+ transition: filter 0.3s ease-in-out;
5
+ }
6
+ .colorize-on-hover:hover,
7
+ .colorize-on-hover:hover [class^='decolorize-'],
8
+ .colorize-on-hover:hover [class*=' decolorize-'] {
9
+ filter: grayscale(0) opacity(1) !important;
10
+ }
11
+
12
+ .decolorize-7 {
13
+ filter: grayscale(1) opacity(0.7);
14
+ }
15
+ .decolorize-6 {
16
+ filter: grayscale(1) opacity(0.6);
17
+ }
18
+ .decolorize-5 {
19
+ filter: grayscale(1) opacity(0.5);
20
+ }
21
+ .decolorize-4 {
22
+ filter: grayscale(1) opacity(0.4);
23
+ }
24
+
25
+ /*
26
+ * Twitter opacity(0.7): #ababab > #868686
27
+ * == Following computation does NOT work ==
28
+ * Discord opacity(0.7): #6c6c6c > (0.7 * (#fff - #ababab) = #868686 = x * (#fff - #6c6c6c) <=> x = 0.7 * ((#fff - #ababab) / (#fff - #6c6c6c)) = 0.7 * ((255 - 171) / (255 - 108)) = 0.4)
29
+ */