@brillout/docpress 0.6.7 → 0.6.9
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.
- package/MobileHeader.tsx +3 -3
- package/PageLayout.tsx +1 -1
- package/components/CodeBlockTransformer.css +0 -1
- package/components/Link.tsx +61 -48
- package/config/resolveHeadingsData.ts +291 -0
- package/config/resolvePageContext.ts +14 -157
- package/css/code.css +5 -0
- package/dist/+config.js +4 -4
- package/dist/parsePageSections.d.ts +12 -0
- package/dist/{markdownHeadingsVitePlugin.js → parsePageSections.js} +24 -27
- package/dist/vite.config.js +6 -6
- package/installSectionUrlHashs.ts +2 -1
- package/navigation/Navigation-items.css +15 -15
- package/navigation/Navigation-layout.css +5 -5
- package/navigation/Navigation.client.ts +4 -40
- package/navigation/Navigation.tsx +83 -88
- package/navigation/initMobileNavigation.ts +32 -0
- package/navigation/initPressKit.ts +16 -0
- package/navigation/navigation-fullscreen/NavigationFullscreenButton.css +1 -1
- package/navigation/navigation-fullscreen/initNavigationFullscreen.ts +1 -1
- package/package.json +25 -24
- package/{markdownHeadingsVitePlugin.ts → parsePageSections.ts} +28 -32
- package/parseTitle.ts +2 -85
- package/renderer/onRenderHtml.tsx +10 -5
- package/types/Heading.ts +36 -32
- package/types.d.ts +1 -1
- package/vite.config.ts +2 -2
- package/dist/markdownHeadingsVitePlugin.d.ts +0 -13
package/dist/+config.js
CHANGED
|
@@ -5,11 +5,11 @@ export default {
|
|
|
5
5
|
client: 'import:@brillout/docpress/renderer/client:doesNotExist',
|
|
6
6
|
meta: {
|
|
7
7
|
Page: {
|
|
8
|
-
env: { client: false, server: true }
|
|
8
|
+
env: { client: false, server: true },
|
|
9
9
|
},
|
|
10
10
|
// Vike already defines the setting 'name', but we redundantly define it here for older Vike versions (otherwise older Vike versions will complain that 'name` is an unknown config).
|
|
11
11
|
name: {
|
|
12
|
-
env: { config: true }
|
|
13
|
-
}
|
|
14
|
-
}
|
|
12
|
+
env: { config: true },
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
15
|
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { parsePageSections };
|
|
2
|
+
export type { PageSection };
|
|
3
|
+
type PageSection = {
|
|
4
|
+
pageSectionTitle: string;
|
|
5
|
+
pageSectionId: string | null;
|
|
6
|
+
pageSectionLevel: number;
|
|
7
|
+
};
|
|
8
|
+
declare function parsePageSections(): {
|
|
9
|
+
name: string;
|
|
10
|
+
enforce: string;
|
|
11
|
+
transform: (code: string, id: string) => Promise<string | undefined>;
|
|
12
|
+
};
|
|
@@ -34,14 +34,14 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
34
34
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
35
|
}
|
|
36
36
|
};
|
|
37
|
-
export {
|
|
37
|
+
export { parsePageSections };
|
|
38
38
|
import { assert } from './utils/assert.js';
|
|
39
39
|
import { determineSectionUrlHash } from './utils/determineSectionUrlHash.js';
|
|
40
40
|
import os from 'os';
|
|
41
|
-
function
|
|
41
|
+
function parsePageSections() {
|
|
42
42
|
var _this = this;
|
|
43
43
|
return {
|
|
44
|
-
name: '
|
|
44
|
+
name: '@brillout/docpress:parsePageSections',
|
|
45
45
|
enforce: 'pre',
|
|
46
46
|
transform: function (code, id) { return __awaiter(_this, void 0, void 0, function () {
|
|
47
47
|
var codeNew;
|
|
@@ -52,11 +52,11 @@ function markdownHeadingsVitePlugin() {
|
|
|
52
52
|
codeNew = transform(code);
|
|
53
53
|
return [2 /*return*/, codeNew];
|
|
54
54
|
});
|
|
55
|
-
}); }
|
|
55
|
+
}); },
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
function transform(code) {
|
|
59
|
-
var
|
|
59
|
+
var pageSections = [];
|
|
60
60
|
var isCodeBlock = false;
|
|
61
61
|
var codeNew = code
|
|
62
62
|
.split('\n')
|
|
@@ -74,47 +74,44 @@ function transform(code) {
|
|
|
74
74
|
return line;
|
|
75
75
|
}
|
|
76
76
|
if (line.startsWith('#')) {
|
|
77
|
-
var _a =
|
|
78
|
-
|
|
77
|
+
var _a = parsePageSection(line), pageSectionId = _a.pageSectionId, pageSectionLevel = _a.pageSectionLevel, pageSectionTitle = _a.pageSectionTitle, headingHtml = _a.headingHtml;
|
|
78
|
+
pageSections.push({ pageSectionId: pageSectionId, pageSectionLevel: pageSectionLevel, pageSectionTitle: pageSectionTitle });
|
|
79
79
|
return headingHtml;
|
|
80
80
|
}
|
|
81
81
|
return line;
|
|
82
82
|
})
|
|
83
83
|
.join('\n');
|
|
84
|
-
var
|
|
85
|
-
.map(function (
|
|
84
|
+
var exportCode = "export const pageSectionsExport = [".concat(pageSections
|
|
85
|
+
.map(function (pageSection) { return JSON.stringify(pageSection); })
|
|
86
86
|
.join(', '), "];");
|
|
87
|
-
codeNew += "\n\n".concat(
|
|
87
|
+
codeNew += "\n\n".concat(exportCode, "\n");
|
|
88
88
|
return codeNew;
|
|
89
89
|
}
|
|
90
|
-
function
|
|
90
|
+
function parsePageSection(line) {
|
|
91
91
|
var _a;
|
|
92
92
|
var _b = line.split(' '), lineBegin = _b[0], lineWords = _b.slice(1);
|
|
93
93
|
assert(lineBegin.split('#').join('') === '', { line: line, lineWords: lineWords });
|
|
94
|
-
var
|
|
94
|
+
var pageSectionLevel = lineBegin.length;
|
|
95
95
|
var titleMdx = lineWords.join(' ');
|
|
96
96
|
assert(!titleMdx.startsWith(' '), { line: line, lineWords: lineWords });
|
|
97
97
|
assert(titleMdx, { line: line, lineWords: lineWords });
|
|
98
|
-
var
|
|
99
|
-
|
|
100
|
-
anchor: titleMdx
|
|
101
|
-
};
|
|
98
|
+
var pageSectionTitle = titleMdx;
|
|
99
|
+
var anchor = titleMdx;
|
|
102
100
|
{
|
|
103
|
-
// Support custom anchor
|
|
101
|
+
// Support custom anchor: `## Some Title{#custom-anchor}`
|
|
104
102
|
var customAnchor = (_a = /(?<={#).*(?=})/g.exec(titleMdx)) === null || _a === void 0 ? void 0 : _a[0];
|
|
105
103
|
if (customAnchor) {
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
anchor = customAnchor;
|
|
105
|
+
pageSectionTitle = titleMdx.replace(/{#.*}/g, '');
|
|
108
106
|
}
|
|
109
107
|
}
|
|
110
|
-
var
|
|
111
|
-
var
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
var
|
|
115
|
-
var
|
|
116
|
-
|
|
117
|
-
return heading;
|
|
108
|
+
var pageSectionId = determineSectionUrlHash(anchor);
|
|
109
|
+
var titleParsed = parseTitle(pageSectionTitle);
|
|
110
|
+
assert(pageSectionId === null || pageSectionId.length > 0);
|
|
111
|
+
var headingId = pageSectionId === null ? '' : " id=\"".concat(pageSectionId, "\"");
|
|
112
|
+
var headingHtml = "<h".concat(pageSectionLevel).concat(headingId, ">").concat(titleParsed, "</h").concat(pageSectionLevel, ">");
|
|
113
|
+
var pageSection = { pageSectionLevel: pageSectionLevel, pageSectionTitle: pageSectionTitle, pageSectionId: pageSectionId, headingHtml: headingHtml };
|
|
114
|
+
return pageSection;
|
|
118
115
|
}
|
|
119
116
|
function parseTitle(titleMarkdown) {
|
|
120
117
|
var parts = [];
|
package/dist/vite.config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import mdx from '@mdx-js/rollup';
|
|
2
2
|
import react from '@vitejs/plugin-react-swc';
|
|
3
3
|
import vike from 'vike/plugin';
|
|
4
|
-
import {
|
|
4
|
+
import { parsePageSections } from './parsePageSections.js';
|
|
5
5
|
import rehypePrettyCode from 'rehype-pretty-code';
|
|
6
6
|
import remarkGfm from 'remark-gfm';
|
|
7
7
|
import { transformerNotationDiff } from '@shikijs/transformers';
|
|
@@ -12,22 +12,22 @@ var remarkPlugins = [remarkGfm];
|
|
|
12
12
|
var config = {
|
|
13
13
|
root: root,
|
|
14
14
|
plugins: [
|
|
15
|
-
|
|
15
|
+
parsePageSections(),
|
|
16
16
|
mdx({ rehypePlugins: rehypePlugins, remarkPlugins: remarkPlugins }),
|
|
17
17
|
// @vitejs/plugin-react-swc needs to be added *after* the mdx plugins
|
|
18
18
|
react(),
|
|
19
19
|
vike({
|
|
20
20
|
prerender: {
|
|
21
|
-
noExtraDir: true
|
|
21
|
+
noExtraDir: true,
|
|
22
22
|
},
|
|
23
|
-
includeAssetsImportedByServer: true
|
|
23
|
+
includeAssetsImportedByServer: true,
|
|
24
24
|
}),
|
|
25
25
|
],
|
|
26
26
|
optimizeDeps: { include: ['@mdx-js/react', 'react-dom'] },
|
|
27
27
|
// @ts-ignore
|
|
28
28
|
ssr: {
|
|
29
|
-
noExternal: ['@brillout/docpress']
|
|
29
|
+
noExternal: ['@brillout/docpress'],
|
|
30
30
|
},
|
|
31
|
-
clearScreen: false
|
|
31
|
+
clearScreen: false,
|
|
32
32
|
};
|
|
33
33
|
export default config;
|
|
@@ -27,7 +27,8 @@ function installSectionUrlHashs() {
|
|
|
27
27
|
function assertNavLink(urlHash: string, heading: HTMLHeadingElement) {
|
|
28
28
|
const navigationEl = getNavigationEl()
|
|
29
29
|
{
|
|
30
|
-
const
|
|
30
|
+
const { pathname } = window.location
|
|
31
|
+
const parentNavLinkMatch = Array.from(navigationEl.querySelectorAll(`a[href="${pathname}"]`))
|
|
31
32
|
assert(parentNavLinkMatch.length === 1)
|
|
32
33
|
}
|
|
33
34
|
{
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
.nav-item code {
|
|
9
9
|
font-size: 0.9em;
|
|
10
10
|
}
|
|
11
|
-
.nav-item-
|
|
11
|
+
.nav-item-level-1 + .nav-item-level-4 {
|
|
12
12
|
margin-top: -2px;
|
|
13
13
|
}
|
|
14
|
-
.nav-item-
|
|
14
|
+
.nav-item-level-4 {
|
|
15
15
|
margin-top: 14px;
|
|
16
16
|
margin-bottom: -1px;
|
|
17
17
|
color: #999;
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
padding-right: 4px;
|
|
23
23
|
text-decoration: none;
|
|
24
24
|
}
|
|
25
|
-
.nav-column:first-of-type > .nav-
|
|
25
|
+
.nav-column:first-of-type > .nav-items-level-1-group:first-of-type > .nav-item-level-1:first-of-type {
|
|
26
26
|
margin-top: 20px;
|
|
27
27
|
}
|
|
28
|
-
.nav-item-
|
|
28
|
+
.nav-item-level-1 {
|
|
29
29
|
margin-top: 30px;
|
|
30
30
|
font-size: 15.4px;
|
|
31
31
|
text-transform: uppercase;
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
padding-right: 4px;
|
|
38
38
|
text-decoration: none;
|
|
39
39
|
}
|
|
40
|
-
.nav-item-
|
|
40
|
+
.nav-item-level-2 {
|
|
41
41
|
text-decoration: none;
|
|
42
42
|
font-size: 14.4px;
|
|
43
43
|
font-weight: 400;
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
padding-top: var(--padding);
|
|
50
50
|
padding-bottom: var(--padding);
|
|
51
51
|
}
|
|
52
|
-
.nav-item-
|
|
52
|
+
.nav-item-level-3 {
|
|
53
53
|
font-size: 12px;
|
|
54
54
|
font-weight: 400;
|
|
55
55
|
letter-spacing: 0.15ch;
|
|
@@ -61,28 +61,28 @@
|
|
|
61
61
|
padding: var(--padding) 0;
|
|
62
62
|
padding-left: calc(var(--padding-left-global) + var(--padding-left-additional));
|
|
63
63
|
}
|
|
64
|
-
html.navigation-fullscreen .nav-item-
|
|
64
|
+
html.navigation-fullscreen .nav-item-level-3 {
|
|
65
65
|
border-right: 4px solid #eee;
|
|
66
66
|
}
|
|
67
|
-
.nav-item-
|
|
67
|
+
.nav-item-level-3.nav-item-first-of-its-kind {
|
|
68
68
|
padding-top: calc(var(--padding) * 1.6);
|
|
69
69
|
}
|
|
70
|
-
.nav-item-
|
|
70
|
+
.nav-item-level-3.nav-item-last-of-its-kind {
|
|
71
71
|
padding-bottom: calc(var(--padding) * 2);
|
|
72
72
|
}
|
|
73
|
-
.nav-item-
|
|
74
|
-
.nav-item-
|
|
73
|
+
.nav-item-level-2,
|
|
74
|
+
.nav-item-level-3 {
|
|
75
75
|
position: relative;
|
|
76
76
|
}
|
|
77
77
|
/*
|
|
78
|
-
.nav-item-
|
|
78
|
+
.nav-item-level-2.is-active .nav-item-text{
|
|
79
79
|
background-color: var(--background-color);
|
|
80
80
|
}
|
|
81
81
|
*/
|
|
82
|
-
.nav-item-
|
|
82
|
+
.nav-item-level-2.is-active {
|
|
83
83
|
background-color: var(--background-color);
|
|
84
84
|
}
|
|
85
|
-
.nav-item-
|
|
85
|
+
.nav-item-level-3.is-active:before {
|
|
86
86
|
display: block;
|
|
87
87
|
content: '';
|
|
88
88
|
position: absolute;
|
|
@@ -93,7 +93,7 @@ html.navigation-fullscreen .nav-item-h3 {
|
|
|
93
93
|
background-color: var(--background-color);
|
|
94
94
|
z-index: 10;
|
|
95
95
|
}
|
|
96
|
-
.nav-item-
|
|
96
|
+
.nav-item-level-3.is-active-last:after {
|
|
97
97
|
display: block;
|
|
98
98
|
content: '';
|
|
99
99
|
position: absolute;
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
margin-top: 25px;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
#navigation-mask {
|
|
32
|
+
#mobile-navigation-mask {
|
|
33
33
|
position: fixed;
|
|
34
34
|
width: 100%;
|
|
35
35
|
height: 100vh;
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
height: 100vh;
|
|
48
48
|
top: 0;
|
|
49
49
|
}
|
|
50
|
-
#navigation-mask {
|
|
50
|
+
#mobile-navigation-mask {
|
|
51
51
|
display: none;
|
|
52
52
|
}
|
|
53
53
|
}
|
|
@@ -83,10 +83,10 @@
|
|
|
83
83
|
/* `position: sticky` doesn't seem to work on mobile */
|
|
84
84
|
position: fixed;
|
|
85
85
|
}
|
|
86
|
-
body:not(.show-
|
|
86
|
+
body:not(.mobile-show-navigation) #navigation-container {
|
|
87
87
|
transform: translateX(calc(-1 * var(--width)));
|
|
88
88
|
}
|
|
89
|
-
body:not(.show-
|
|
89
|
+
body:not(.mobile-show-navigation) #mobile-navigation-mask {
|
|
90
90
|
display: none;
|
|
91
91
|
}
|
|
92
92
|
#mobile-header {
|
|
@@ -118,7 +118,7 @@ html.navigation-fullscreen .navigation-content > .nav-column {
|
|
|
118
118
|
flex-grow: 1;
|
|
119
119
|
max-width: 350px;
|
|
120
120
|
}
|
|
121
|
-
html.navigation-fullscreen .nav-column > .nav-
|
|
121
|
+
html.navigation-fullscreen .nav-column > .nav-items-level-1-group:first-child > .nav-item-level-1:first-child {
|
|
122
122
|
margin-top: 0px;
|
|
123
123
|
}
|
|
124
124
|
html.navigation-fullscreen {
|
|
@@ -1,43 +1,7 @@
|
|
|
1
1
|
import { initNavigationFullscreen } from './navigation-fullscreen/initNavigationFullscreen'
|
|
2
|
+
import { initMobileNavigation } from './initMobileNavigation'
|
|
3
|
+
import { initPressKit } from './initPressKit'
|
|
2
4
|
|
|
3
|
-
activateNavigationMask()
|
|
4
|
-
activateMenuToggle()
|
|
5
5
|
initNavigationFullscreen()
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
}
|
|
6
|
+
initMobileNavigation()
|
|
7
|
+
initPressKit()
|
|
@@ -1,44 +1,40 @@
|
|
|
1
1
|
export { Navigation }
|
|
2
2
|
export { NavigationMask }
|
|
3
|
+
export type { NavigationData }
|
|
4
|
+
export type { NavItem }
|
|
3
5
|
|
|
4
6
|
import React from 'react'
|
|
5
7
|
import { NavigationHeader } from './NavigationHeader'
|
|
6
|
-
import { Heading, HeadingDetached } from '../types/Heading'
|
|
7
8
|
import { assert, Emoji, assertWarning, jsxToTextContent } from '../utils/server'
|
|
8
9
|
import './Navigation.css'
|
|
9
10
|
import { NavigationFullscreenClose } from './navigation-fullscreen/NavigationFullscreenButton'
|
|
10
11
|
|
|
12
|
+
type NavigationData = Parameters<typeof Navigation>[0]
|
|
13
|
+
|
|
11
14
|
function Navigation({
|
|
12
|
-
|
|
15
|
+
navItems,
|
|
16
|
+
navItemsAll,
|
|
17
|
+
currentUrl,
|
|
18
|
+
isDetachedPage,
|
|
13
19
|
}: {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
20
|
+
navItems: NavItem[]
|
|
21
|
+
navItemsAll: NavItem[]
|
|
22
|
+
currentUrl: string
|
|
23
|
+
isDetachedPage: boolean
|
|
19
24
|
}) {
|
|
20
|
-
const currentUrl = pageContext.urlPathname
|
|
21
25
|
return (
|
|
22
26
|
<>
|
|
23
27
|
<div id="navigation-container">
|
|
24
28
|
<NavigationHeader />
|
|
25
|
-
{
|
|
29
|
+
{isDetachedPage && (
|
|
26
30
|
<>
|
|
27
|
-
{
|
|
28
|
-
<NavigationContent
|
|
29
|
-
id="navigation-content-detached"
|
|
30
|
-
headingsProcessed={pageContext.headingsOfDetachedPage}
|
|
31
|
-
currentUrl={currentUrl}
|
|
32
|
-
/>
|
|
31
|
+
{navItems.length > 1 && (
|
|
32
|
+
<NavigationContent id="navigation-content-detached" navItems={navItems} currentUrl={currentUrl} />
|
|
33
33
|
)}
|
|
34
34
|
<DetachedPageNote />
|
|
35
35
|
</>
|
|
36
36
|
)}
|
|
37
|
-
<NavigationContent
|
|
38
|
-
id="navigation-content-main"
|
|
39
|
-
headingsProcessed={pageContext.headingsProcessed}
|
|
40
|
-
currentUrl={currentUrl}
|
|
41
|
-
/>
|
|
37
|
+
<NavigationContent id="navigation-content-main" navItems={navItemsAll} currentUrl={currentUrl} />
|
|
42
38
|
{/* <ScrollOverlay /> */}
|
|
43
39
|
<NavigationFullscreenClose />
|
|
44
40
|
</div>
|
|
@@ -47,26 +43,39 @@ function Navigation({
|
|
|
47
43
|
}
|
|
48
44
|
|
|
49
45
|
function NavigationMask() {
|
|
50
|
-
return <div id="navigation-mask" />
|
|
46
|
+
return <div id="mobile-navigation-mask" />
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
type NavItem = {
|
|
50
|
+
level: number
|
|
51
|
+
url?: string | null
|
|
52
|
+
title: string | JSX.Element
|
|
53
|
+
titleInNav: string | JSX.Element
|
|
54
|
+
}
|
|
55
|
+
type NavItemComputed = NavItem & {
|
|
56
|
+
isActive: boolean
|
|
57
|
+
isActiveFirst: boolean
|
|
58
|
+
isActiveLast: boolean
|
|
59
|
+
isFirstOfItsKind: boolean
|
|
60
|
+
isLastOfItsKind: boolean
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
function NavigationContent(props: {
|
|
54
64
|
id: 'navigation-content-main' | 'navigation-content-detached'
|
|
55
|
-
|
|
65
|
+
navItems: NavItem[]
|
|
56
66
|
currentUrl: string
|
|
57
67
|
}) {
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
const headingsGrouped = groupHeadings(headings)
|
|
68
|
+
const navItemsWithComputed = addComputedProps(props.navItems, props.currentUrl)
|
|
69
|
+
const navItemsGrouped = groupByLevel1(navItemsWithComputed)
|
|
61
70
|
|
|
62
71
|
return (
|
|
63
72
|
<div id={props.id} className="navigation-content">
|
|
64
73
|
<div className="nav-column" style={{ position: 'relative' }}>
|
|
65
|
-
{
|
|
66
|
-
<div className="nav-
|
|
67
|
-
<
|
|
68
|
-
{
|
|
69
|
-
<
|
|
74
|
+
{navItemsGrouped.map((navItemLevel1, i) => (
|
|
75
|
+
<div className="nav-items-level-1-group" key={i}>
|
|
76
|
+
<NavItemComponent navItem={navItemLevel1} />
|
|
77
|
+
{navItemLevel1.navItemChilds.map((navItem, j) => (
|
|
78
|
+
<NavItemComponent navItem={navItem} key={j} />
|
|
70
79
|
))}
|
|
71
80
|
</div>
|
|
72
81
|
))}
|
|
@@ -75,32 +84,20 @@ function NavigationContent(props: {
|
|
|
75
84
|
)
|
|
76
85
|
}
|
|
77
86
|
|
|
78
|
-
function
|
|
79
|
-
|
|
87
|
+
function NavItemComponent({
|
|
88
|
+
navItem,
|
|
80
89
|
}: {
|
|
81
|
-
|
|
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
|
-
}
|
|
90
|
+
navItem: NavItemComputed
|
|
94
91
|
}) {
|
|
95
|
-
assert([1, 2, 3, 4].includes(
|
|
96
|
-
if (
|
|
97
|
-
assert(
|
|
92
|
+
assert([1, 2, 3, 4].includes(navItem.level), navItem)
|
|
93
|
+
if (navItem.level === 1 || navItem.level === 4) {
|
|
94
|
+
assert(navItem.url === undefined)
|
|
98
95
|
} else {
|
|
99
|
-
const sectionTitle = jsxToTextContent(
|
|
96
|
+
const sectionTitle = jsxToTextContent(navItem.title)
|
|
100
97
|
assertWarning(
|
|
101
|
-
|
|
98
|
+
navItem.url,
|
|
102
99
|
`${jsxToTextContent(
|
|
103
|
-
|
|
100
|
+
navItem.titleInNav,
|
|
104
101
|
)} is missing a URL hash. Use \`<h2 id="url-hash">${sectionTitle}</h2>\` instead of \`## ${sectionTitle}\`.`,
|
|
105
102
|
)
|
|
106
103
|
}
|
|
@@ -108,73 +105,71 @@ function Heading({
|
|
|
108
105
|
<a
|
|
109
106
|
className={[
|
|
110
107
|
'nav-item',
|
|
111
|
-
'nav-item-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
108
|
+
'nav-item-level-' + navItem.level,
|
|
109
|
+
navItem.isActive && ' is-active',
|
|
110
|
+
navItem.isActiveFirst && ' is-active-first',
|
|
111
|
+
navItem.isActiveLast && ' is-active-last',
|
|
112
|
+
navItem.isFirstOfItsKind && 'nav-item-first-of-its-kind',
|
|
113
|
+
navItem.isLastOfItsKind && 'nav-item-last-of-its-kind',
|
|
117
114
|
]
|
|
118
115
|
.filter(Boolean)
|
|
119
116
|
.join(' ')}
|
|
120
|
-
href={
|
|
117
|
+
href={navItem.url ?? undefined}
|
|
121
118
|
>
|
|
122
|
-
{/* <span className="nav-item-text">{
|
|
123
|
-
{
|
|
119
|
+
{/* <span className="nav-item-text">{navItem.titleInNav}</span> */}
|
|
120
|
+
{navItem.titleInNav}
|
|
124
121
|
</a>
|
|
125
122
|
)
|
|
126
123
|
}
|
|
127
124
|
|
|
128
|
-
function
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
if (
|
|
133
|
-
|
|
125
|
+
function groupByLevel1<T extends { level: number }>(navItems: T[]) {
|
|
126
|
+
const navItemsGrouped: (T & { navItemChilds: T[] })[] = []
|
|
127
|
+
const levelMin: number = Math.min(...navItems.map((h) => h.level))
|
|
128
|
+
navItems.forEach((navItem) => {
|
|
129
|
+
if (navItem.level === levelMin) {
|
|
130
|
+
navItemsGrouped.push({ ...navItem, navItemChilds: [] })
|
|
134
131
|
} else {
|
|
135
|
-
|
|
132
|
+
navItemsGrouped[navItemsGrouped.length - 1].navItemChilds.push(navItem)
|
|
136
133
|
}
|
|
137
134
|
})
|
|
138
|
-
return
|
|
135
|
+
return navItemsGrouped
|
|
139
136
|
}
|
|
140
137
|
|
|
141
|
-
function
|
|
142
|
-
return
|
|
143
|
-
assert([1, 2, 3, 4].includes(
|
|
138
|
+
function addComputedProps(navItems: NavItem[], currentUrl: string): NavItemComputed[] {
|
|
139
|
+
return navItems.map((navItem, i) => {
|
|
140
|
+
assert([1, 2, 3, 4].includes(navItem.level), navItem)
|
|
144
141
|
|
|
145
|
-
const
|
|
146
|
-
const
|
|
142
|
+
const navItemPrevious = navItems[i - 1]
|
|
143
|
+
const navItemNext = navItems[i + 1]
|
|
147
144
|
|
|
148
145
|
let isActiveFirst = false
|
|
149
146
|
let isActiveLast = false
|
|
150
147
|
let isActive = false
|
|
151
|
-
if (
|
|
152
|
-
assert(
|
|
148
|
+
if (navItem.url === currentUrl) {
|
|
149
|
+
assert(navItem.level === 2, { currentUrl })
|
|
153
150
|
isActive = true
|
|
154
151
|
isActiveFirst = true
|
|
155
|
-
if (
|
|
152
|
+
if (navItemNext?.level !== 3) {
|
|
156
153
|
isActiveLast = true
|
|
157
154
|
}
|
|
158
155
|
}
|
|
159
|
-
if (
|
|
156
|
+
if (navItem.level === 3) {
|
|
160
157
|
isActive = true
|
|
161
|
-
if (
|
|
158
|
+
if (navItemNext?.level !== 3) {
|
|
162
159
|
isActiveLast = true
|
|
163
160
|
}
|
|
164
161
|
}
|
|
165
162
|
|
|
166
|
-
const isFirstOfItsKind =
|
|
167
|
-
const isLastOfItsKind =
|
|
163
|
+
const isFirstOfItsKind = navItem.level !== navItemPrevious?.level
|
|
164
|
+
const isLastOfItsKind = navItem.level !== navItemNext?.level
|
|
168
165
|
|
|
169
166
|
return {
|
|
170
|
-
...
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
isLastOfItsKind,
|
|
177
|
-
},
|
|
167
|
+
...navItem,
|
|
168
|
+
isActive,
|
|
169
|
+
isActiveFirst,
|
|
170
|
+
isActiveLast,
|
|
171
|
+
isFirstOfItsKind,
|
|
172
|
+
isLastOfItsKind,
|
|
178
173
|
}
|
|
179
174
|
})
|
|
180
175
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export { initMobileNavigation }
|
|
2
|
+
|
|
3
|
+
function initMobileNavigation() {
|
|
4
|
+
activateMobileShowNavigationToggle()
|
|
5
|
+
activateMobileNavigationMask()
|
|
6
|
+
autoHideNavigationOverlayOnLinkClick()
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function activateMobileShowNavigationToggle() {
|
|
10
|
+
const toggle = document.getElementById('mobile-show-navigation-toggle')!
|
|
11
|
+
toggle.onclick = toggleNavigation
|
|
12
|
+
}
|
|
13
|
+
function activateMobileNavigationMask() {
|
|
14
|
+
const navigationMask = document.getElementById('mobile-navigation-mask')!
|
|
15
|
+
navigationMask.onclick = toggleNavigation
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function autoHideNavigationOverlayOnLinkClick() {
|
|
19
|
+
document.addEventListener('click', (ev: any) => {
|
|
20
|
+
const el = ev.target
|
|
21
|
+
if (!el || !('classList' in el)) return
|
|
22
|
+
if (!el.classList.contains('nav-item')) return
|
|
23
|
+
hideNavigation()
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function toggleNavigation() {
|
|
28
|
+
document.body.classList.toggle('mobile-show-navigation')
|
|
29
|
+
}
|
|
30
|
+
function hideNavigation() {
|
|
31
|
+
document.body.classList.remove('mobile-show-navigation')
|
|
32
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { initPressKit }
|
|
2
|
+
|
|
3
|
+
function initPressKit() {
|
|
4
|
+
// Right click navigation header => show /press
|
|
5
|
+
navigationHeaderRightClickInterceptor()
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function navigationHeaderRightClickInterceptor() {
|
|
9
|
+
const navHeader = document.getElementById('navigation-header')!
|
|
10
|
+
if (!navHeader.classList.contains('press-kit')) return
|
|
11
|
+
if (window.location.pathname === '/press') return
|
|
12
|
+
navHeader.oncontextmenu = (ev) => {
|
|
13
|
+
ev.preventDefault()
|
|
14
|
+
window.location.href = '/press'
|
|
15
|
+
}
|
|
16
|
+
}
|