@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,111 @@
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 iconLanguages from '../icons/languages.svg'
7
+ import { usePageContext } from '../renderer/usePageContext'
8
+
9
+ export { NavigationHeader }
10
+
11
+ function NavigationHeader() {
12
+ const pageContext = usePageContext()
13
+ return (
14
+ <div
15
+ id="navigation-header"
16
+ className={pageContext.config.pressKit && 'press-kit'}
17
+ style={{
18
+ display: 'flex',
19
+ flexDirection: 'column',
20
+ alignItems: 'center',
21
+ marginBottom: -5
22
+ }}
23
+ >
24
+ <a
25
+ id="navigation-header-logo"
26
+ style={{
27
+ display: 'flex',
28
+ alignItems: 'center',
29
+ color: 'inherit',
30
+ justifyContent: 'left',
31
+ textDecoration: 'none',
32
+ paddingTop: 12,
33
+ paddingBottom: 7,
34
+ ...pageContext.config.navHeaderWrapperStyle
35
+ }}
36
+ href="/"
37
+ >
38
+ {pageContext.config.navHeader}
39
+ </a>
40
+ <Links />
41
+ </div>
42
+ )
43
+ }
44
+
45
+ function Links() {
46
+ const pageContext = usePageContext()
47
+ const { projectInfo, i18n } = pageContext.config
48
+ const iconI18n = !i18n ? null : (
49
+ <LinkIcon
50
+ className="decolorize-4"
51
+ icon={iconLanguages}
52
+ href={'/languages'}
53
+ style={{ height: 21, position: 'relative', top: 0, left: 0 }}
54
+ />
55
+ )
56
+ return (
57
+ <div
58
+ style={{
59
+ display: 'flex',
60
+ alignItems: 'center',
61
+ paddingTop: 0,
62
+ justifyContent: 'left'
63
+ }}
64
+ >
65
+ <LinkIcon className="decolorize-4" icon={iconGithub} href={projectInfo.githubRepository} />
66
+ <LinkIcon className="decolorize-6" icon={iconDiscord} href={projectInfo.discordInvite} />
67
+ <LinkIcon className="decolorize-7" icon={iconTwitter} href={projectInfo.twitterProfile} />
68
+ <div className="decolorize-6 colorize-on-hover" id="docsearch-desktop" />
69
+ {iconI18n}
70
+ <ChangelogButton />
71
+ </div>
72
+ )
73
+ }
74
+
75
+ function ChangelogButton() {
76
+ const pageContext = usePageContext()
77
+ const { projectInfo } = pageContext.config
78
+ return (
79
+ <a
80
+ href={`${projectInfo.githubRepository}/blob/main/CHANGELOG.md`}
81
+ className="button colorize-on-hover"
82
+ style={{
83
+ display: 'flex',
84
+ alignItems: 'center',
85
+ padding: '1px 7px',
86
+ marginLeft: 2,
87
+ fontSize: '0.97em',
88
+ color: 'inherit'
89
+ }}
90
+ >
91
+ <span id="version-number" className="decolorize-7">
92
+ v{projectInfo.projectVersion}
93
+ </span>
94
+ <img className="decolorize-6" src={iconChangelog} height={16} style={{ marginLeft: 5 }} />
95
+ </a>
96
+ )
97
+ }
98
+
99
+ function LinkIcon({ className, icon, href, style }: { className: string; icon: string; href: string; style?: any }) {
100
+ return (
101
+ <>
102
+ <a
103
+ className={'colorize-on-hover ' + className}
104
+ href={href}
105
+ style={{ padding: 3, display: 'inline-block', lineHeight: 0 }}
106
+ >
107
+ <img src={icon} height="20" style={style} />
108
+ </a>
109
+ </>
110
+ )
111
+ }
@@ -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: 'absolute', top: 11, right: 11, 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,116 @@
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 (document.body.classList.contains('DocSearch--active')) return
17
+ if (ev.key === 'Escape') toggleNavExpend()
18
+ },
19
+ false
20
+ )
21
+ }
22
+
23
+ function toggleNavExpend() {
24
+ const navContainer = document.getElementById('navigation-container')!
25
+ const scrollPos = navContainer.scrollTop
26
+ document.documentElement.classList.toggle('navigation-fullscreen')
27
+ if (scrollPositionBeforeToggle !== undefined) {
28
+ navContainer.scrollTop = scrollPositionBeforeToggle
29
+ }
30
+ scrollPositionBeforeToggle = scrollPos
31
+ }
32
+
33
+ function updateColumnWidth() {
34
+ const navMinWidth = 299
35
+ const navH1Groups = Array.from(document.querySelectorAll('#navigation-content-main .nav-h1-group'))
36
+ const numberOfColumnsMax = navH1Groups.length
37
+
38
+ const widthAvailable = getViewportWidth()
39
+ const numberOfColumns = Math.max(1, Math.min(numberOfColumnsMax, Math.floor(widthAvailable / navMinWidth)))
40
+
41
+ let columns = navH1Groups.map((navH1Group) => {
42
+ const column = [
43
+ {
44
+ element: navH1Group,
45
+ elementHeight: navH1Group.children.length
46
+ }
47
+ ]
48
+ return column
49
+ })
50
+
51
+ mergeColumns(columns, numberOfColumns)
52
+
53
+ const navContent = document.getElementById('navigation-content-main')!
54
+
55
+ Array.from(navContent.children).forEach((child) => {
56
+ assert(child.className === 'nav-column')
57
+ })
58
+ navContent.innerHTML = ''
59
+
60
+ columns.forEach((column) => {
61
+ const columnEl = document.createElement('div')
62
+ columnEl.className = 'nav-column'
63
+ column.forEach(({ element }) => {
64
+ columnEl.appendChild(element)
65
+ })
66
+ navContent.appendChild(columnEl)
67
+ })
68
+
69
+ const navItemMaxWidth = 350
70
+ navContent.style.maxWidth = `${numberOfColumns * navItemMaxWidth}px`
71
+ }
72
+ function getViewportWidth(): number {
73
+ // `window.innerWidth` inlcudes scrollbar width: https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
74
+ return document.documentElement.clientWidth
75
+ }
76
+
77
+ function mergeColumns<T>(columns: { element: T; elementHeight: number }[][], maxNumberOfColumns: number) {
78
+ assert(columns.length > 0)
79
+ assert(maxNumberOfColumns > 0)
80
+ if (columns.length <= maxNumberOfColumns) {
81
+ return columns
82
+ }
83
+
84
+ let mergeCandidate = {
85
+ i: -1,
86
+ mergeHeight: Infinity
87
+ }
88
+ for (let i = 0; i <= columns.length - 2; i++) {
89
+ const column1 = columns[i + 0]
90
+ const column2 = columns[i + 1]
91
+ const column1Height = sum(column1.map((c) => c.elementHeight))
92
+ const column2Height = sum(column2.map((c) => c.elementHeight))
93
+ const mergeHeight = column1Height + column2Height
94
+ if (mergeCandidate.mergeHeight > mergeHeight) {
95
+ mergeCandidate = {
96
+ i,
97
+ mergeHeight
98
+ }
99
+ }
100
+ }
101
+
102
+ {
103
+ const { i } = mergeCandidate
104
+ assert(-1 < i && i < columns.length - 1, { i, columnsLength: columns.length, maxNumberOfColumns })
105
+ columns[i] = [...columns[i], ...columns[i + 1]]
106
+ columns.splice(i + 1, 1)
107
+ }
108
+
109
+ mergeColumns(columns, maxNumberOfColumns)
110
+ }
111
+
112
+ function sum(arr: number[]): number {
113
+ let total = 0
114
+ arr.forEach((n) => (total += n))
115
+ return total
116
+ }
package/package.json CHANGED
@@ -1,23 +1,14 @@
1
1
  {
2
2
  "name": "@brillout/docpress",
3
- "version": "0.5.39",
3
+ "version": "0.5.40-commit-51be4fa",
4
4
  "scripts": {
5
+ "// Build vite.config.ts": "",
6
+ "build": "rm -rf dist/ && tsc --project tsconfig.vite-config.json",
5
7
  "// Check types while developing": "",
6
8
  "types": "tsc --noEmit --watch",
7
- "// Develop Docpress using demo/": "",
8
- "dev": "pnpm run dev:build && pnpm run dev:start",
9
- "dev:build": "tsup",
10
- "dev:start": "node dist/index.js dev",
11
- "// Build Docpress": "",
12
- "build": "rimraf dist/ && framework-builder",
13
- "// Preview build": "",
14
- "preview": "pnpm run preview:build && pnpm run preview:start",
15
- "preview:build": "pnpm run build && node dist/cli/index.js build",
16
- "preview:start": "node dist/cli/index.js preview",
17
- "// Test": "",
18
- "test": "test-e2e",
19
9
  "// Release": "",
20
10
  "release": "release-me patch",
11
+ "release:commit": "release-me commit",
21
12
  "release:breaking-change": "release-me minor"
22
13
  },
23
14
  "dependencies": {
@@ -26,73 +17,60 @@
26
17
  "@mdx-js/rollup": "^2.0.0",
27
18
  "@vitejs/plugin-react-swc": "^3.3.2",
28
19
  "balloon-css": "^1.2.0",
29
- "express": "^4.17.1",
30
20
  "rehype-pretty-code": "^0.3.2",
31
21
  "remark-gfm": "^3.0.1",
32
22
  "shiki": "^0.10.1",
33
23
  "twemoji": "^13.1.0",
34
- "vike": "^0.4.158",
35
- "vike-contributors": "^0.0.8",
36
- "vite": "^4.3.9"
24
+ "vike-contributors": "^0.0.9"
37
25
  },
38
26
  "type": "module",
39
27
  "exports": {
40
- "./renderer/_default.page.server.js": "./dist/renderer/_default.page.server.js",
41
- "./renderer/_default.page.client.js": "./dist/renderer/_default.page.client.js",
42
- "./renderer/_default.page.server.css": "./dist/renderer/_default.page.server.css",
43
- "./renderer/_default.page.client.css": "./dist/renderer/_default.page.client.css",
44
- ".": "./dist/index.js",
45
- "./features/FeatureList": "./dist/components/features/FeatureList.js",
28
+ "./renderer/onRenderHtml": "./renderer/onRenderHtml.tsx",
29
+ "./renderer/client.ts": "./renderer/client.ts",
30
+ ".": "./index.ts",
31
+ "./features/FeatureList": "./components/features/FeatureList.tsx",
46
32
  "./features/FeatureList.css": {
47
- "browser": "./dist/components/features/FeatureList.css"
33
+ "browser": "./components/features/FeatureList.css"
48
34
  },
49
35
  "./features/initFeatureList": {
50
- "browser": "./dist/components/features/initFeatureList.js"
51
- }
36
+ "browser": "./components/features/initFeatureList.ts"
37
+ },
38
+ "./vite-config": "./dist/vite.config.js",
39
+ "./style": "./css/index.css"
52
40
  },
53
41
  "typesVersions": {
54
42
  "*": {
55
43
  "*": [
56
- "dist/*"
44
+ "./*"
57
45
  ],
58
46
  "types": [
59
- "types.d.ts"
47
+ "./types.d.ts"
48
+ ],
49
+ "vite-config": [
50
+ "./dist/vite.config.d.ts"
60
51
  ],
61
52
  "features/*": [
62
- "dist/components/features/*"
53
+ "./components/features/*"
63
54
  ]
64
55
  }
65
56
  },
66
57
  "peerDependencies": {
58
+ "vike": "^0.4.161",
59
+ "vite": "^4.3.9",
67
60
  "react": "18",
68
61
  "react-dom": "18"
69
62
  },
70
63
  "devDependencies": {
71
- "@brillout/docpress": "link:.",
72
- "@brillout/framework-builder": "^0.1.1",
73
64
  "@brillout/release-me": "^0.1.13",
74
- "@brillout/test-e2e": "^0.5.25",
75
- "@types/express": "^4.17.13",
76
65
  "@types/node": "^15.12.1",
77
66
  "@types/react": "^17.0.44",
78
67
  "@types/react-dom": "^17.0.6",
79
- "docpress": "link:",
80
- "react": "^18.1.0",
81
- "react-dom": "^18.1.0",
82
- "rimraf": "^3.0.2",
83
- "rollup": "^2.74.1",
84
- "tsup": "^7.0.0",
85
- "tsx": "^3.12.1",
68
+ "react": "^18.2.0",
69
+ "react-dom": "^18.2.0",
70
+ "vike": "^0.4.161",
71
+ "vite": "^4.3.9",
86
72
  "typescript": "^4.9.4"
87
73
  },
88
- "bin": {
89
- "docpress": "./bin.js"
90
- },
91
- "files": [
92
- "types.d.ts",
93
- "bin.js",
94
- "dist/"
95
- ],
96
74
  "license": "MIT",
97
75
  "repository": "https://github.com/brillout/docpress",
98
76
  "publishConfig": {
package/parseEmojis.ts ADDED
@@ -0,0 +1,35 @@
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
+ // https://emojipedia.org/construction/
13
+ ':construction:': 0x1f6a7
14
+ /*
15
+ // https://emojipedia.org/red-heart/
16
+ ':heart:': 0x2764,
17
+ */
18
+ }
19
+
20
+ function parseEmojis(html: string) {
21
+ Object.entries(emojiList).forEach(([shortcode, codepoint]) => {
22
+ if (!html.includes(shortcode)) {
23
+ return
24
+ }
25
+ const emojiStr = twemoji.convert.fromCodePoint(codepoint as any)
26
+ let emojiImg: any = twemoji.parse(emojiStr, {
27
+ folder: 'svg',
28
+ ext: '.svg'
29
+ })
30
+ const style = 'height: 1.275em; width: 1.275em; vertical-align: -20%'
31
+ emojiImg = emojiImg.replace('<img class="emoji" ', `<img style="${style}" `)
32
+ html = html.split(shortcode).join(emojiImg)
33
+ })
34
+ return html
35
+ }
package/parseTitle.ts ADDED
@@ -0,0 +1,139 @@
1
+ export { parseTitle }
2
+ export { getHeadingsWithProcessedTitle }
3
+
4
+ import React from 'react'
5
+ import type { HeadingDefinition, HeadingDetachedDefinition, Heading, HeadingDetached } from './types/Heading'
6
+ import { assert, Emoji, EmojiName } from './utils/server'
7
+
8
+ function getHeadingsWithProcessedTitle(config: {
9
+ headings: HeadingDefinition[]
10
+ headingsDetached: HeadingDetachedDefinition[]
11
+ }): {
12
+ headingsProcessed: Heading[]
13
+ headingsDetachedProcessed: HeadingDetached[]
14
+ } {
15
+ const headingsWithoutBreadcrumb: Omit<Heading, 'headingsBreadcrumb'>[] = config.headings.map(
16
+ (heading: HeadingDefinition) => {
17
+ const titleProcessed: JSX.Element = parseTitle(heading.title)
18
+
19
+ const titleInNav = heading.titleInNav || heading.title
20
+ let titleInNavProcessed: JSX.Element
21
+ titleInNavProcessed = parseTitle(titleInNav)
22
+ if ('titleEmoji' in heading) {
23
+ assert(heading.titleEmoji)
24
+ titleInNavProcessed = withEmoji(heading.titleEmoji, titleInNavProcessed)
25
+ }
26
+
27
+ const headingProcessed: Omit<Heading, 'headingsBreadcrumb'> = {
28
+ ...heading,
29
+ title: titleProcessed,
30
+ titleInNav: titleInNavProcessed
31
+ }
32
+ return headingProcessed
33
+ }
34
+ )
35
+
36
+ const headingsProcessed: Heading[] = []
37
+ headingsWithoutBreadcrumb.forEach((heading) => {
38
+ const headingsBreadcrumb = getHeadingsBreadcrumb(heading, headingsProcessed)
39
+ headingsProcessed.push({
40
+ ...heading,
41
+ headingsBreadcrumb
42
+ })
43
+ })
44
+
45
+ const headingsDetachedProcessed = config.headingsDetached.map((headingsDetached) => {
46
+ const { url, title } = headingsDetached
47
+ assert(
48
+ headingsProcessed.find((heading) => heading.url === url) === undefined,
49
+ `remove ${headingsDetached.url} from headingsDetached`
50
+ )
51
+ const titleProcessed = typeof title === 'string' ? parseTitle(title) : title
52
+ return {
53
+ ...headingsDetached,
54
+ level: 2 as const,
55
+ title: titleProcessed,
56
+ titleInNav: titleProcessed,
57
+ headingsBreadcrumb: null
58
+ }
59
+ })
60
+
61
+ assertHeadingsUrl([...headingsProcessed, ...headingsDetachedProcessed])
62
+ return { headingsProcessed, headingsDetachedProcessed }
63
+ }
64
+
65
+ function getHeadingsBreadcrumb(heading: Omit<Heading, 'headingsBreadcrumb'>, headings: Heading[]) {
66
+ const headingsBreadcrumb: Heading[] = []
67
+ let levelCurrent = heading.level
68
+ headings
69
+ .slice()
70
+ .reverse()
71
+ .forEach((parentCandidate) => {
72
+ const isParent = parentCandidate.level < levelCurrent
73
+ if (isParent) {
74
+ levelCurrent = parentCandidate.level
75
+ headingsBreadcrumb.push(parentCandidate)
76
+ }
77
+ })
78
+ return headingsBreadcrumb
79
+ }
80
+
81
+ function assertHeadingsUrl(headings: { url?: null | string }[]) {
82
+ headings.forEach((heading) => {
83
+ if (heading.url) {
84
+ const { url } = heading
85
+ assert(url.startsWith('/'))
86
+ }
87
+ })
88
+ }
89
+
90
+ function parseTitle(title: string): JSX.Element {
91
+ type Part = { nodeType: 'text' | 'code'; content: string }
92
+ const parts: Part[] = []
93
+ let current: Part | undefined
94
+ title.split('').forEach((letter) => {
95
+ if (letter === '`') {
96
+ if (current?.nodeType === 'code') {
97
+ // </code>
98
+ parts.push(current)
99
+ current = undefined
100
+ } else {
101
+ // <code>
102
+ if (current) {
103
+ parts.push(current)
104
+ }
105
+ current = { nodeType: 'code', content: '' }
106
+ }
107
+ } else {
108
+ if (!current) {
109
+ current = { nodeType: 'text', content: '' }
110
+ }
111
+ current.content += letter
112
+ }
113
+ })
114
+ if (current) {
115
+ parts.push(current)
116
+ }
117
+
118
+ const titleJsx = React.createElement(
119
+ React.Fragment,
120
+ {},
121
+ ...parts.map((part, i) =>
122
+ React.createElement(part.nodeType === 'code' ? 'code' : React.Fragment, { key: i }, part.content)
123
+ )
124
+ )
125
+
126
+ return titleJsx
127
+ }
128
+
129
+ function withEmoji(name: EmojiName, title: string | JSX.Element): JSX.Element {
130
+ const style = { fontSize: '1.4em' }
131
+ //return React.createElement(React.Fragment, null, Emoji({ name, style }), ' ', title)
132
+ return React.createElement(
133
+ 'span',
134
+ { style },
135
+ Emoji({ name }),
136
+ ' ',
137
+ React.createElement('span', { style: { fontSize: '1rem' } }, title)
138
+ )
139
+ }
@@ -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
+ export { onRenderHtml }
2
+
3
+ import ReactDOMServer from 'react-dom/server'
4
+ import React from 'react'
5
+ import { escapeInject, dangerouslySkipEscape } from 'vike/server'
6
+ import { PageLayout } from '../PageLayout'
7
+ import { resolvePageContext, PageContextOriginal } from '../config/resolvePageContext'
8
+ import { getDocSearchJS, getDocSearchCSS } from '../algolia/DocSearch'
9
+ import { parseEmojis } from '../parseEmojis'
10
+ import { assert } from '../utils/server'
11
+
12
+ async function onRenderHtml(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 (!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
+ }