@rocket/js 0.1.2 → 0.2.0
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/README.md +8 -2
- package/dist-types/exports/layouts/atlasBlog.d.ts +2 -0
- package/dist-types/exports/layouts/atlasBlog.d.ts.map +1 -0
- package/dist-types/exports/types/rocket.d.ts +60 -2
- package/dist-types/exports/types/rocket.d.ts.map +1 -1
- package/dist-types/exports/types.d.ts +1 -1
- package/dist-types/exports/types.d.ts.map +1 -1
- package/dist-types/src/PageData.d.ts +3 -1
- package/dist-types/src/PageData.d.ts.map +1 -1
- package/dist-types/src/RocketJsDemo.d.ts.map +1 -1
- package/dist-types/src/SocialPreviewPlayground.d.ts +1 -0
- package/dist-types/src/SocialPreviewPlayground.d.ts.map +1 -1
- package/dist-types/src/asyncMessage.d.ts +5 -0
- package/dist-types/src/asyncMessage.d.ts.map +1 -1
- package/dist-types/src/cli/RocketBuild.d.ts.map +1 -1
- package/dist-types/src/cli/RocketCli.d.ts.map +1 -1
- package/dist-types/src/cli/RocketStart.d.ts +6 -1
- package/dist-types/src/cli/RocketStart.d.ts.map +1 -1
- package/dist-types/src/component-hydration.d.ts.map +1 -1
- package/dist-types/src/components/RocketDrawer.d.ts +8 -0
- package/dist-types/src/components/RocketDrawer.d.ts.map +1 -1
- package/dist-types/src/components/RocketSocialLink.d.ts.map +1 -1
- package/dist-types/src/config.d.ts.map +1 -1
- package/dist-types/src/feeds.d.ts +38 -0
- package/dist-types/src/feeds.d.ts.map +1 -0
- package/dist-types/src/hydration/hydrationLoader.d.ts +13 -4
- package/dist-types/src/hydration/hydrationLoader.d.ts.map +1 -1
- package/dist-types/src/icons.d.ts.map +1 -1
- package/dist-types/src/layouts/atlas/atlasBlogLayout.d.ts +42 -0
- package/dist-types/src/layouts/atlas/atlasBlogLayout.d.ts.map +1 -0
- package/dist-types/src/layouts/atlas/atlasDocLayout.d.ts.map +1 -1
- package/dist-types/src/layouts/atlas/atlasHeroLayout.d.ts.map +1 -1
- package/dist-types/src/layouts/atlas/atlasNotFoundLayout.d.ts.map +1 -1
- package/dist-types/src/layouts/layout-helper.d.ts +3 -3
- package/dist-types/src/layouts/layout-helper.d.ts.map +1 -1
- package/dist-types/src/markdownHook.d.ts.map +1 -1
- package/dist-types/src/menu.d.ts +8 -3
- package/dist-types/src/menu.d.ts.map +1 -1
- package/dist-types/src/menus/MainMenu.d.ts.map +1 -1
- package/dist-types/src/{development-page-module-loader.d.ts → page-module-loader.d.ts} +7 -2
- package/dist-types/src/page-module-loader.d.ts.map +1 -0
- package/dist-types/src/page-runtime.d.ts +11 -0
- package/dist-types/src/page-runtime.d.ts.map +1 -1
- package/dist-types/src/pages.d.ts.map +1 -1
- package/dist-types/src/route-pattern.d.ts +10 -0
- package/dist-types/src/route-pattern.d.ts.map +1 -0
- package/dist-types/src/siteDiscoverability.d.ts +4 -0
- package/dist-types/src/siteDiscoverability.d.ts.map +1 -1
- package/dist-types/src/socialPreviewImages.d.ts +2 -1
- package/dist-types/src/socialPreviewImages.d.ts.map +1 -1
- package/dist-types/src/static-params.d.ts +33 -0
- package/dist-types/src/static-params.d.ts.map +1 -0
- package/dist-types/src/transform.d.ts +4 -0
- package/dist-types/src/transform.d.ts.map +1 -1
- package/dist-types/src/wds-plugin.d.ts.map +1 -1
- package/exports/layouts/atlasBlog.js +11 -0
- package/exports/types/rocket.test.ts +26 -0
- package/exports/types/rocket.ts +70 -2
- package/exports/types.ts +7 -0
- package/package.json +15 -31
- package/src/PageData.js +12 -2
- package/src/RocketJsDemo.js +1 -0
- package/src/SocialPreviewPlayground.js +26 -20
- package/src/asyncMessage.js +8 -2
- package/src/cli/RocketBuild.js +110 -13
- package/src/cli/RocketCli.js +11 -1
- package/src/cli/RocketStart.js +60 -16
- package/src/cli/cli.js +10 -1
- package/src/component-hydration.js +23 -3
- package/src/components/RocketDrawer.js +44 -10
- package/src/components/RocketSocialLink.js +26 -2
- package/src/config.js +33 -4
- package/src/feeds.js +212 -0
- package/src/hydration/hydrationLoader.js +80 -48
- package/src/icons.js +5 -0
- package/src/layouts/atlas/atlasBlog.css +143 -0
- package/src/layouts/atlas/atlasBlogLayout.js +234 -0
- package/src/layouts/atlas/atlasDocLayout.js +3 -2
- package/src/layouts/atlas/atlasHeroLayout.js +4 -6
- package/src/layouts/atlas/atlasNotFoundLayout.js +9 -21
- package/src/layouts/layout-helper.js +5 -5
- package/src/layouts/layout.js +2 -2
- package/src/loaded-page-module.js +3 -1
- package/src/markdownCompiler.js +2 -2
- package/src/markdownHook.js +7 -2
- package/src/menu.js +25 -19
- package/src/menus/MainMenu.js +10 -4
- package/src/{static-page-module-loader.js → page-module-loader.js} +6 -1
- package/src/page-pagination.js +2 -2
- package/src/page-runtime.js +48 -3
- package/src/pages.js +47 -56
- package/src/publicAssets.js +2 -2
- package/src/route-pattern.js +21 -0
- package/src/siteDiscoverability.js +14 -1
- package/src/socialPreviewImages.js +80 -14
- package/src/standalone-demo-url.js +2 -2
- package/src/static-params.js +114 -0
- package/src/transform.js +89 -22
- package/src/wds-plugin.js +16 -3
- package/dist-types/src/development-page-module-loader.d.ts.map +0 -1
- package/dist-types/src/static-page-module-loader.d.ts +0 -15
- package/dist-types/src/static-page-module-loader.d.ts.map +0 -1
- package/src/development-page-module-loader.js +0 -29
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { html } from 'lit';
|
|
2
|
+
import { document } from '../layout-helper.js';
|
|
3
|
+
import { resolve } from '../../resolve.js';
|
|
4
|
+
import { webAwesomeComponents } from '@rocket/js/components/web-awesome.js';
|
|
5
|
+
import { addBootstrapIconLibrary } from '../layout.js';
|
|
6
|
+
import { rocketDemoComponents } from '../../components.js';
|
|
7
|
+
import {
|
|
8
|
+
renderHeaderLogo,
|
|
9
|
+
renderHeaderNavLinks,
|
|
10
|
+
renderSocials,
|
|
11
|
+
renderStylesheets,
|
|
12
|
+
} from './atlasDocLayout.js';
|
|
13
|
+
|
|
14
|
+
/** @typedef {import('@rocket/js/types.js').BlogData} BlogData */
|
|
15
|
+
/** @typedef {import('@rocket/js/types.js').PageCollectionEntry} PageCollectionEntry */
|
|
16
|
+
|
|
17
|
+
/** @type {import('@rocket/js/types.js').Components} */
|
|
18
|
+
export const atlasBlogComponents = {
|
|
19
|
+
'rocket-social-link': {
|
|
20
|
+
file: './components/RocketSocialLink.js',
|
|
21
|
+
className: 'RocketSocialLink',
|
|
22
|
+
loading: 'server',
|
|
23
|
+
},
|
|
24
|
+
...rocketDemoComponents,
|
|
25
|
+
...webAwesomeComponents,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {string} date date-only ISO string from Page Metadata
|
|
30
|
+
* @param {string | undefined} language
|
|
31
|
+
*/
|
|
32
|
+
export function formatBlogDate(date, language) {
|
|
33
|
+
const parsed = new Date(`${date}T00:00:00Z`);
|
|
34
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
35
|
+
return date;
|
|
36
|
+
}
|
|
37
|
+
return new Intl.DateTimeFormat(language || 'en', {
|
|
38
|
+
dateStyle: 'long',
|
|
39
|
+
timeZone: 'UTC',
|
|
40
|
+
}).format(parsed);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {string[] | undefined} tags
|
|
45
|
+
* @param {BlogData} data
|
|
46
|
+
*/
|
|
47
|
+
export function renderBlogTags(tags, data) {
|
|
48
|
+
if (!tags || tags.length === 0) {
|
|
49
|
+
return '';
|
|
50
|
+
}
|
|
51
|
+
return html`
|
|
52
|
+
<ul class="atlas-blog-tags">
|
|
53
|
+
${tags.map(
|
|
54
|
+
tag => html`
|
|
55
|
+
<li>
|
|
56
|
+
${data.tagPathPrefix
|
|
57
|
+
? html`<a href=${blogTagPath(data.tagPathPrefix, tag)} rel="tag">${tag}</a>`
|
|
58
|
+
: html`<span>${tag}</span>`}
|
|
59
|
+
</li>
|
|
60
|
+
`,
|
|
61
|
+
)}
|
|
62
|
+
</ul>
|
|
63
|
+
`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {string} tagPathPrefix
|
|
68
|
+
* @param {string} tag
|
|
69
|
+
*/
|
|
70
|
+
export function blogTagPath(tagPathPrefix, tag) {
|
|
71
|
+
const prefix = tagPathPrefix.endsWith('/') ? tagPathPrefix : `${tagPathPrefix}/`;
|
|
72
|
+
return `${prefix}${tag}/`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @param {import('@rocket/js/types.js').PageMetadata} metadata
|
|
77
|
+
* @param {BlogData} data
|
|
78
|
+
* @param {string | undefined} language
|
|
79
|
+
*/
|
|
80
|
+
export function renderBlogByline(metadata, data, language) {
|
|
81
|
+
const authors = metadata.authors || [];
|
|
82
|
+
if (!metadata.date && authors.length === 0 && !(metadata.tags || []).length) {
|
|
83
|
+
return '';
|
|
84
|
+
}
|
|
85
|
+
return html`
|
|
86
|
+
<div class="atlas-blog-byline">
|
|
87
|
+
${metadata.date
|
|
88
|
+
? html`<time datetime=${metadata.date}>${formatBlogDate(metadata.date, language)}</time>`
|
|
89
|
+
: ''}
|
|
90
|
+
${authors.length ? html`<span class="atlas-blog-authors">${authors.join(', ')}</span>` : ''}
|
|
91
|
+
${renderBlogTags(metadata.tags, data)}
|
|
92
|
+
</div>
|
|
93
|
+
`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @param {PageCollectionEntry[]} items
|
|
98
|
+
* @param {BlogData} data
|
|
99
|
+
* @param {string | undefined} language
|
|
100
|
+
*/
|
|
101
|
+
export function renderBlogPostList(items, data, language) {
|
|
102
|
+
if (items.length === 0) {
|
|
103
|
+
return html`<p class="atlas-blog-empty">No posts yet.</p>`;
|
|
104
|
+
}
|
|
105
|
+
return html`
|
|
106
|
+
<ol class="atlas-blog-post-list" reversed>
|
|
107
|
+
${items.map(
|
|
108
|
+
item => html`
|
|
109
|
+
<li class="atlas-blog-post-card">
|
|
110
|
+
<h2><a href=${item.url}>${item.metadata.title}</a></h2>
|
|
111
|
+
${item.metadata.date
|
|
112
|
+
? html`<time datetime=${item.metadata.date}
|
|
113
|
+
>${formatBlogDate(item.metadata.date, language)}</time
|
|
114
|
+
>`
|
|
115
|
+
: ''}
|
|
116
|
+
${item.metadata.description ? html`<p>${item.metadata.description}</p>` : ''}
|
|
117
|
+
${renderBlogTags(item.metadata.tags, data)}
|
|
118
|
+
</li>
|
|
119
|
+
`,
|
|
120
|
+
)}
|
|
121
|
+
</ol>
|
|
122
|
+
`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @param {import('@rocket/js/types.js').PagePagination | undefined} pagination
|
|
127
|
+
*/
|
|
128
|
+
export function renderBlogPagination(pagination) {
|
|
129
|
+
if (!pagination || pagination.totalPages <= 1) {
|
|
130
|
+
return '';
|
|
131
|
+
}
|
|
132
|
+
return html`
|
|
133
|
+
<nav class="atlas-blog-pagination" aria-label="Blog pages">
|
|
134
|
+
${pagination.previousPath
|
|
135
|
+
? html`<a href=${pagination.previousPath} rel="prev">Newer posts</a>`
|
|
136
|
+
: html`<span></span>`}
|
|
137
|
+
<span>Page ${pagination.currentPage} of ${pagination.totalPages}</span>
|
|
138
|
+
${pagination.nextPath
|
|
139
|
+
? html`<a href=${pagination.nextPath} rel="next">Older posts</a>`
|
|
140
|
+
: html`<span></span>`}
|
|
141
|
+
</nav>
|
|
142
|
+
`;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Shared Atlas blog document chrome for post and index layouts.
|
|
147
|
+
*
|
|
148
|
+
* @param {import('../../PageData.js').PageData} pageData
|
|
149
|
+
* @param {BlogData} data
|
|
150
|
+
* @param {unknown} mainContent
|
|
151
|
+
*/
|
|
152
|
+
function atlasBlogDocument(pageData, data, mainContent) {
|
|
153
|
+
addBootstrapIconLibrary(pageData);
|
|
154
|
+
const cssPath = resolve('@rocket/js/docs/assets/prism-one-light.css', import.meta);
|
|
155
|
+
const siteName = pageData.siteHeadMetadata?.siteName ?? pageData.title;
|
|
156
|
+
const headContent = data.headContent?.({ pageData });
|
|
157
|
+
|
|
158
|
+
return document(
|
|
159
|
+
pageData,
|
|
160
|
+
html`
|
|
161
|
+
<div class="atlas-blog">
|
|
162
|
+
<header class="atlas-header atlas-blog-header">
|
|
163
|
+
<a href=${data.headerData.homeLink} class="logo-header">
|
|
164
|
+
${renderHeaderLogo(data.headerData.logo, siteName)}
|
|
165
|
+
</a>
|
|
166
|
+
<nav class="atlas-header-links" aria-label="Primary navigation">
|
|
167
|
+
${renderHeaderNavLinks(data.headerData.navLinks)}
|
|
168
|
+
${renderSocials(data.headerData.socials, siteName)}
|
|
169
|
+
</nav>
|
|
170
|
+
</header>
|
|
171
|
+
<main id="content" class="atlas-blog-content">${mainContent}</main>
|
|
172
|
+
</div>
|
|
173
|
+
`,
|
|
174
|
+
{
|
|
175
|
+
menu: false,
|
|
176
|
+
headContent: html`
|
|
177
|
+
<link rel="stylesheet" href=${cssPath} />
|
|
178
|
+
<link
|
|
179
|
+
rel="stylesheet"
|
|
180
|
+
href="${resolve('@awesome.me/webawesome/dist/styles/webawesome.css', import.meta)}"
|
|
181
|
+
/>
|
|
182
|
+
<link rel="stylesheet" href="${resolve('@rocket/js/layouts/atlasDoc.css', import.meta)}" />
|
|
183
|
+
<link rel="stylesheet" href="${resolve('@rocket/js/layouts/atlasBlog.css', import.meta)}" />
|
|
184
|
+
${data.feedPath
|
|
185
|
+
? html`<link
|
|
186
|
+
rel="alternate"
|
|
187
|
+
type="application/atom+xml"
|
|
188
|
+
href=${data.feedPath}
|
|
189
|
+
title=${siteName}
|
|
190
|
+
/>`
|
|
191
|
+
: ''}
|
|
192
|
+
${renderStylesheets(data.stylesheets)} ${headContent}
|
|
193
|
+
`,
|
|
194
|
+
},
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** @type {import('@rocket/js/types.js').Layout<BlogData>} */
|
|
199
|
+
export const atlasPostLayout = (pageData, data) => {
|
|
200
|
+
const language = pageData.siteHeadMetadata?.language;
|
|
201
|
+
return atlasBlogDocument(
|
|
202
|
+
pageData,
|
|
203
|
+
data,
|
|
204
|
+
html`
|
|
205
|
+
<article class="atlas-blog-post">
|
|
206
|
+
${renderBlogByline(pageData.metadata, data, language)} ${pageData.content}
|
|
207
|
+
</article>
|
|
208
|
+
`,
|
|
209
|
+
);
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
/** @type {import('@rocket/js/types.js').Layout<BlogData>} */
|
|
213
|
+
export const atlasBlogIndexLayout = (pageData, data) => {
|
|
214
|
+
const language = pageData.siteHeadMetadata?.language;
|
|
215
|
+
const items = pageData.pagination?.items || [];
|
|
216
|
+
return atlasBlogDocument(
|
|
217
|
+
pageData,
|
|
218
|
+
data,
|
|
219
|
+
html`
|
|
220
|
+
<section class="atlas-blog-index">
|
|
221
|
+
<div class="atlas-blog-intro">
|
|
222
|
+
${pageData.content}
|
|
223
|
+
${data.feedPath
|
|
224
|
+
? html`<a class="atlas-blog-feed-link" href=${data.feedPath}>
|
|
225
|
+
<rocket-icon library="bootstrap" name="rss" aria-hidden="true"></rocket-icon>
|
|
226
|
+
Feed
|
|
227
|
+
</a>`
|
|
228
|
+
: ''}
|
|
229
|
+
</div>
|
|
230
|
+
${renderBlogPostList(items, data, language)} ${renderBlogPagination(pageData.pagination)}
|
|
231
|
+
</section>
|
|
232
|
+
`,
|
|
233
|
+
);
|
|
234
|
+
};
|
|
@@ -210,6 +210,7 @@ export const atlasDocLayout = (pageData, data) => {
|
|
|
210
210
|
const serializedToc = serializeToc(pageData.toc);
|
|
211
211
|
const navigationIconServerBudget =
|
|
212
212
|
data.navigationIconServerBudget ?? DEFAULT_ATLAS_DOC_NAVIGATION_ICON_SERVER_BUDGET;
|
|
213
|
+
const headContent = data.headContent?.({ pageData });
|
|
213
214
|
|
|
214
215
|
return document(
|
|
215
216
|
pageData,
|
|
@@ -269,14 +270,14 @@ export const atlasDocLayout = (pageData, data) => {
|
|
|
269
270
|
`,
|
|
270
271
|
{
|
|
271
272
|
menu: false,
|
|
272
|
-
|
|
273
|
+
headContent: html`
|
|
273
274
|
<link rel="stylesheet" href=${cssPath} />
|
|
274
275
|
<link
|
|
275
276
|
rel="stylesheet"
|
|
276
277
|
href="${resolve('@awesome.me/webawesome/dist/styles/webawesome.css', import.meta)}"
|
|
277
278
|
/>
|
|
278
279
|
<link rel="stylesheet" href="${resolve('@rocket/js/layouts/atlasDoc.css', import.meta)}" />
|
|
279
|
-
${renderStylesheets(data.stylesheets)}
|
|
280
|
+
${renderStylesheets(data.stylesheets)} ${headContent}
|
|
280
281
|
`,
|
|
281
282
|
},
|
|
282
283
|
);
|
|
@@ -262,10 +262,8 @@ export const atlasHeroLayout = (pageData, data) => {
|
|
|
262
262
|
const heroEyebrow = hero.eyebrow ?? hero.sloganTop;
|
|
263
263
|
const heroTitle = hero.title ?? hero.sloganBottom ?? pageData.title;
|
|
264
264
|
const siteName = pageData.siteHeadMetadata?.siteName ?? pageData.title;
|
|
265
|
-
const navLinks = data.headerData.navLinks ?? [
|
|
266
|
-
|
|
267
|
-
{ text: 'Examples', href: '/examples' },
|
|
268
|
-
];
|
|
265
|
+
const navLinks = data.headerData.navLinks ?? [{ text: 'Docs', href: hero.documentationLink }];
|
|
266
|
+
const headContent = data.headContent?.({ pageData });
|
|
269
267
|
|
|
270
268
|
return document(
|
|
271
269
|
pageData,
|
|
@@ -329,14 +327,14 @@ export const atlasHeroLayout = (pageData, data) => {
|
|
|
329
327
|
`,
|
|
330
328
|
{
|
|
331
329
|
menu: false,
|
|
332
|
-
|
|
330
|
+
headContent: html`
|
|
333
331
|
<link rel="stylesheet" href=${cssPath} />
|
|
334
332
|
<link
|
|
335
333
|
rel="stylesheet"
|
|
336
334
|
href="${resolve('@awesome.me/webawesome/dist/styles/webawesome.css', import.meta)}"
|
|
337
335
|
/>
|
|
338
336
|
<link rel="stylesheet" href="${resolve('@rocket/js/layouts/atlasHero.css', import.meta)}" />
|
|
339
|
-
${renderStylesheets(data.stylesheets)}
|
|
337
|
+
${renderStylesheets(data.stylesheets)} ${headContent}
|
|
340
338
|
`,
|
|
341
339
|
},
|
|
342
340
|
);
|
|
@@ -1,27 +1,11 @@
|
|
|
1
1
|
import { html } from 'lit';
|
|
2
2
|
import { document } from '../layout-helper.js';
|
|
3
3
|
import { resolve } from '../../resolve.js';
|
|
4
|
-
import { renderStylesheets } from './atlasDocLayout.js';
|
|
4
|
+
import { renderHeaderLogo, renderStylesheets } from './atlasDocLayout.js';
|
|
5
5
|
|
|
6
6
|
/** @type {import('@rocket/js/types.js').Components} */
|
|
7
7
|
export const atlasNotFoundComponents = {};
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* Renders the header logo.
|
|
11
|
-
* @param {Array<string>} logo
|
|
12
|
-
*/
|
|
13
|
-
function renderHeaderLogo(logo) {
|
|
14
|
-
if (logo.length === 1) {
|
|
15
|
-
return html`<img src=${logo[0]} alt="Logo" width="130" />`;
|
|
16
|
-
} else if (logo.length === 2) {
|
|
17
|
-
return html`
|
|
18
|
-
<img src=${logo[0]} alt="Logo" width="36" />
|
|
19
|
-
<img src=${logo[1]} alt="Logo Text" width="88" />
|
|
20
|
-
`;
|
|
21
|
-
}
|
|
22
|
-
return html`<b>Header logo should only contain one or two images.</b>`;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
9
|
/**
|
|
26
10
|
* @param {Array<{url: string, name: string, label?: string}>} socials
|
|
27
11
|
*/
|
|
@@ -33,6 +17,8 @@ function renderSocialLinks(socials) {
|
|
|
33
17
|
export const atlasNotFoundLayout = (pageData, data) => {
|
|
34
18
|
const homeLink = data.headerData.homeLink || '/';
|
|
35
19
|
const rocketLogo = data.headerData.logo[0];
|
|
20
|
+
const siteName = pageData.siteHeadMetadata?.siteName ?? pageData.title;
|
|
21
|
+
const headContent = data.headContent?.({ pageData });
|
|
36
22
|
|
|
37
23
|
return document(
|
|
38
24
|
pageData,
|
|
@@ -40,7 +26,7 @@ export const atlasNotFoundLayout = (pageData, data) => {
|
|
|
40
26
|
<div class="atlas-not-found">
|
|
41
27
|
<header class="atlas-not-found-header">
|
|
42
28
|
<a href=${homeLink} class="atlas-not-found-logo">
|
|
43
|
-
${renderHeaderLogo(data.headerData.logo)}
|
|
29
|
+
${renderHeaderLogo(data.headerData.logo, siteName)}
|
|
44
30
|
</a>
|
|
45
31
|
<nav class="atlas-not-found-links" aria-label="Project links">
|
|
46
32
|
${renderSocialLinks(data.headerData.socials)}
|
|
@@ -54,18 +40,20 @@ export const atlasNotFoundLayout = (pageData, data) => {
|
|
|
54
40
|
<div class="atlas-not-found-stars"></div>
|
|
55
41
|
<div class="atlas-not-found-orbit"></div>
|
|
56
42
|
<p class="atlas-not-found-code">404</p>
|
|
57
|
-
|
|
43
|
+
${rocketLogo
|
|
44
|
+
? html`<img class="atlas-not-found-rocket" src=${rocketLogo} alt="" />`
|
|
45
|
+
: html``}
|
|
58
46
|
</div>
|
|
59
47
|
</main>
|
|
60
48
|
</div>
|
|
61
49
|
`,
|
|
62
50
|
{
|
|
63
51
|
menu: false,
|
|
64
|
-
|
|
52
|
+
headContent: html`<link
|
|
65
53
|
rel="stylesheet"
|
|
66
54
|
href="${resolve('@rocket/js/layouts/atlasNotFound.css', import.meta)}"
|
|
67
55
|
/>
|
|
68
|
-
${renderStylesheets(data.stylesheets)}`,
|
|
56
|
+
${renderStylesheets(data.stylesheets)} ${headContent}`,
|
|
69
57
|
},
|
|
70
58
|
);
|
|
71
59
|
};
|
|
@@ -11,7 +11,7 @@ import { defaultHtmlMenu } from '../menu.js';
|
|
|
11
11
|
* @param {Object} [options]
|
|
12
12
|
* @param {LitHTML} [options.title]
|
|
13
13
|
* @param {'html' | false} [options.menu] render a default menu. set to false if you want your own
|
|
14
|
-
* @param {LitHTML} [options.
|
|
14
|
+
* @param {LitHTML} [options.headContent]
|
|
15
15
|
*/
|
|
16
16
|
export function document(
|
|
17
17
|
data,
|
|
@@ -19,7 +19,7 @@ export function document(
|
|
|
19
19
|
{
|
|
20
20
|
title = data.siteHeadMetadata?.title ?? data.title,
|
|
21
21
|
menu = 'html',
|
|
22
|
-
|
|
22
|
+
headContent = undefined,
|
|
23
23
|
} = {},
|
|
24
24
|
) {
|
|
25
25
|
const siteHeadMetadata = data.siteHeadMetadata;
|
|
@@ -40,12 +40,12 @@ export function document(
|
|
|
40
40
|
}
|
|
41
41
|
</style>`
|
|
42
42
|
: ''}
|
|
43
|
-
${data.clientCode} ${
|
|
43
|
+
${data.clientCode} ${headContent}
|
|
44
44
|
</head>
|
|
45
45
|
<body>
|
|
46
46
|
${menu
|
|
47
|
-
? html`<
|
|
48
|
-
<
|
|
47
|
+
? html`<nav id="menu" aria-label="Site">${defaultHtmlMenu(data.pageTree)}</nav>
|
|
48
|
+
<main id="content">${content}</main>`
|
|
49
49
|
: content}
|
|
50
50
|
</body>
|
|
51
51
|
</html>`;
|
package/src/layouts/layout.js
CHANGED
|
@@ -9,7 +9,7 @@ export const layout = data => {
|
|
|
9
9
|
addBootstrapIconLibrary(data);
|
|
10
10
|
return document(data, data.content, {
|
|
11
11
|
menu: 'html',
|
|
12
|
-
|
|
12
|
+
headContent: html`
|
|
13
13
|
<link
|
|
14
14
|
rel="stylesheet"
|
|
15
15
|
href="${resolve('@rocket/js/docs/assets/prism-one-light.css', import.meta)}"
|
|
@@ -27,7 +27,7 @@ export const singleDemoLayout = data => {
|
|
|
27
27
|
addBootstrapIconLibrary(data);
|
|
28
28
|
return document(data, data.content, {
|
|
29
29
|
menu: false,
|
|
30
|
-
|
|
30
|
+
headContent: html`
|
|
31
31
|
<link
|
|
32
32
|
rel="stylesheet"
|
|
33
33
|
href="${resolve('@awesome.me/webawesome/dist/styles/webawesome.css', import.meta)}"
|
|
@@ -92,6 +92,8 @@ function normalizeMarkdownPageContent(rawModule, { parseComponents }) {
|
|
|
92
92
|
*/
|
|
93
93
|
function hasBrowserLoadedComponents(components) {
|
|
94
94
|
return Object.values(components).some(
|
|
95
|
-
component =>
|
|
95
|
+
component =>
|
|
96
|
+
component.loading === 'client' ||
|
|
97
|
+
(typeof component.loading === 'string' && component.loading.startsWith('hydrate:')),
|
|
96
98
|
);
|
|
97
99
|
}
|
package/src/markdownCompiler.js
CHANGED
|
@@ -5,7 +5,7 @@ import rehypeRaw from 'rehype-raw';
|
|
|
5
5
|
import { unified } from 'unified';
|
|
6
6
|
import { visit } from 'unist-util-visit';
|
|
7
7
|
import { extractMdCode } from './extractCode.js';
|
|
8
|
-
import { mdToJs, mdToJsSingleDemo } from './transform.js';
|
|
8
|
+
import { isDemoCodeNode, mdToJs, mdToJsSingleDemo } from './transform.js';
|
|
9
9
|
import { init, parse as parseExports } from 'es-module-lexer';
|
|
10
10
|
import ts from 'typescript';
|
|
11
11
|
import { parseRequestDemoMetadata } from './requestDemoMetadata.js';
|
|
@@ -235,7 +235,7 @@ function extractDemoNames() {
|
|
|
235
235
|
/** @type {import('unist-util-visit').Visitor} */
|
|
236
236
|
const visitor = _node => {
|
|
237
237
|
const node = /** @type {import('mdast').Code} */ (_node);
|
|
238
|
-
if (node
|
|
238
|
+
if (isDemoCodeNode(node) && typeof node.value === 'string') {
|
|
239
239
|
for (const exported of parseExports(node.value)[1]) {
|
|
240
240
|
demoNames.push(exported.ln || exported.n);
|
|
241
241
|
}
|
package/src/markdownHook.js
CHANGED
|
@@ -102,7 +102,11 @@ export async function resolve(specifier, context, nextResolve) {
|
|
|
102
102
|
},
|
|
103
103
|
};
|
|
104
104
|
if (match[0] === 'Setup' && isLocalFile(url)) {
|
|
105
|
-
|
|
105
|
+
// Fire-and-forget: awaiting a reply here can deadlock. The main thread
|
|
106
|
+
// blocks in Atomics.wait during e.g. a nested module.register() call, so
|
|
107
|
+
// it may be unable to answer until this resolve returns. postMessage
|
|
108
|
+
// delivery is ordered, which is all the dependency tracking needs.
|
|
109
|
+
sendPort.postMessage({
|
|
106
110
|
parent: getPath(/** @type {string} */ (context.parentURL)),
|
|
107
111
|
url: getPath(resolve.url),
|
|
108
112
|
});
|
|
@@ -116,7 +120,8 @@ export async function resolve(specifier, context, nextResolve) {
|
|
|
116
120
|
...resolve.importAttributes,
|
|
117
121
|
type: 'cache' + lastReload.toString(36),
|
|
118
122
|
};
|
|
119
|
-
|
|
123
|
+
// Fire-and-forget, see above.
|
|
124
|
+
sendPort.postMessage({
|
|
120
125
|
parent: getPath(/** @type {string} */ (context.parentURL)),
|
|
121
126
|
url: getPath(resolve.url),
|
|
122
127
|
});
|
package/src/menu.js
CHANGED
|
@@ -34,13 +34,14 @@ export function treeFromPages(pages) {
|
|
|
34
34
|
continue;
|
|
35
35
|
}
|
|
36
36
|
const parts = getMenuParts(url, module);
|
|
37
|
+
if (parts.some(part => part.startsWith(':'))) {
|
|
38
|
+
// Dynamic paths have no single public URL, so they get no menu entry.
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
37
41
|
let obj = children;
|
|
38
42
|
/** @type {any} */
|
|
39
43
|
let last = {};
|
|
40
44
|
for (const part of parts) {
|
|
41
|
-
if (part.startsWith(':')) {
|
|
42
|
-
break;
|
|
43
|
-
}
|
|
44
45
|
const get = obj.find(leaf => leaf.name === part);
|
|
45
46
|
if (!get) {
|
|
46
47
|
/** @type {import('@rocket/js/types.js').PageTree[]} */
|
|
@@ -137,19 +138,25 @@ function sortRecursive(children) {
|
|
|
137
138
|
}
|
|
138
139
|
|
|
139
140
|
/**
|
|
141
|
+
* The itemFn receives the rendered child list (or lit `nothing`) and must place
|
|
142
|
+
* it inside the returned item so nested lists stay valid HTML.
|
|
143
|
+
*
|
|
140
144
|
* @param {import("@rocket/js/types.js").PageTree} tree
|
|
141
145
|
* @param {string} listTagName
|
|
142
|
-
* @param {(name: string, url: string, module: import("@rocket/js/types.js").Module, linkText: string) => import("lit").TemplateResult} itemFn
|
|
146
|
+
* @param {(name: string, url: string, module: import("@rocket/js/types.js").Module, linkText: string, children: import("lit").TemplateResult | typeof nothing) => import("lit").TemplateResult} itemFn
|
|
147
|
+
* @returns {import("lit").TemplateResult}
|
|
143
148
|
*/
|
|
144
149
|
export function treeToHtml(tree, listTagName, itemFn) {
|
|
145
150
|
return html`${unsafeHTML(`<${listTagName}>`)}${join(
|
|
146
|
-
tree.children.map(page =>
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
tree.children.map(page =>
|
|
152
|
+
itemFn(
|
|
153
|
+
page.name,
|
|
154
|
+
page.url,
|
|
155
|
+
page.module,
|
|
156
|
+
page.linkText,
|
|
157
|
+
page.children.length ? treeToHtml(page, listTagName, itemFn) : nothing,
|
|
158
|
+
),
|
|
159
|
+
),
|
|
153
160
|
nothing,
|
|
154
161
|
)}${unsafeHTML(`</${listTagName}>`)}`;
|
|
155
162
|
}
|
|
@@ -158,14 +165,13 @@ export function treeToHtml(tree, listTagName, itemFn) {
|
|
|
158
165
|
* @param {import('@rocket/js/types.js').PageTree} pageTree
|
|
159
166
|
*/
|
|
160
167
|
export function defaultHtmlMenu(pageTree) {
|
|
161
|
-
return treeToHtml(
|
|
162
|
-
|
|
163
|
-
'
|
|
164
|
-
|
|
165
|
-
html`<
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
);
|
|
168
|
+
return treeToHtml(pageTree, 'ul', (_name, url, module, linkText, children) => {
|
|
169
|
+
const menu = module.config.menu;
|
|
170
|
+
const noLink = !url || menu === false || (typeof menu === 'object' && menu?.noLink);
|
|
171
|
+
return html`<li>
|
|
172
|
+
${noLink ? html`<span>${linkText}</span>` : html`<a href=${url}>${linkText}</a>`}${children}
|
|
173
|
+
</li>`;
|
|
174
|
+
});
|
|
169
175
|
}
|
|
170
176
|
|
|
171
177
|
/** Runs on: import-hook */
|
package/src/menus/MainMenu.js
CHANGED
|
@@ -32,15 +32,21 @@ export class MainMenu extends LitElement {
|
|
|
32
32
|
*/
|
|
33
33
|
list(page, depth = 0) {
|
|
34
34
|
const title = page.linkText;
|
|
35
|
+
const isCurrent = page.url === this.currentPath;
|
|
35
36
|
/** @type {any} */
|
|
36
|
-
const classes = { current:
|
|
37
|
+
const classes = { current: isCurrent };
|
|
37
38
|
const level = `lvl-${depth}`;
|
|
38
39
|
classes[level] = true;
|
|
39
40
|
return html`
|
|
40
41
|
<li>
|
|
41
|
-
|
|
42
|
-
>${title}</
|
|
43
|
-
|
|
42
|
+
${page.menuNoLink
|
|
43
|
+
? html`<span class=${classMap(classes)}>${title}</span>`
|
|
44
|
+
: html`<a
|
|
45
|
+
href=${ifDefined(page.url)}
|
|
46
|
+
class=${classMap(classes)}
|
|
47
|
+
aria-current=${ifDefined(isCurrent ? 'page' : undefined)}
|
|
48
|
+
>${title}</a
|
|
49
|
+
>`}
|
|
44
50
|
${page.children.length > 0
|
|
45
51
|
? html`<ul>
|
|
46
52
|
${page.children.map(child => this.list(child, depth + 1))}
|
|
@@ -3,7 +3,12 @@ import { parseComponents } from './components.js';
|
|
|
3
3
|
|
|
4
4
|
/** @typedef {import('./page-runtime.js').PageModuleLoaderOptions} PageModuleLoaderOptions */
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* The Page Module Loader used by both the development server and static builds.
|
|
8
|
+
* Loading goes through Rocket's import hooks, which behave the same in both
|
|
9
|
+
* runtime environments.
|
|
10
|
+
*/
|
|
11
|
+
export function createPageModuleLoader() {
|
|
7
12
|
return {
|
|
8
13
|
/**
|
|
9
14
|
* @param {PageModuleLoaderOptions} options
|
package/src/page-pagination.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { routePattern } from './route-pattern.js';
|
|
2
2
|
import { PageData } from './PageData.js';
|
|
3
3
|
import { normalizeDocumentPath } from './standalone-demo-url.js';
|
|
4
4
|
|
|
@@ -229,7 +229,7 @@ function parsePaginatedArchivePath(pathname) {
|
|
|
229
229
|
* @param {string} routePath
|
|
230
230
|
*/
|
|
231
231
|
function matchPagePath(pathname, origin, routePath) {
|
|
232
|
-
const pattern =
|
|
232
|
+
const pattern = routePattern(routePath);
|
|
233
233
|
return pattern.exec(pathname, origin);
|
|
234
234
|
}
|
|
235
235
|
|