mdorigin 0.1.7 → 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 +12 -0
- package/dist/adapters/cloudflare.d.ts +40 -4
- package/dist/adapters/cloudflare.js +163 -7
- package/dist/adapters/node.js +2 -2
- package/dist/cli/build-cloudflare.js +27 -2
- package/dist/cli/help.js +5 -4
- package/dist/cli/init-cloudflare.js +7 -1
- package/dist/cli/main.js +5 -0
- package/dist/cli/sync-cloudflare-r2.d.ts +1 -0
- package/dist/cli/sync-cloudflare-r2.js +47 -0
- package/dist/cloudflare-runtime.d.ts +1 -1
- package/dist/cloudflare.d.ts +42 -6
- package/dist/cloudflare.js +246 -10
- package/dist/core/content-store.d.ts +1 -0
- package/dist/core/content-store.js +8 -1
- package/dist/core/extensions.d.ts +5 -9
- package/dist/core/markdown.js +32 -4
- package/dist/core/request-handler.js +46 -60
- package/dist/core/site-config.d.ts +4 -10
- package/dist/core/site-config.js +18 -10
- package/dist/html/template.d.ts +5 -9
- package/dist/html/template.js +33 -27
- package/dist/html/theme.d.ts +1 -2
- package/dist/html/theme.js +12 -628
- package/dist/index-builder.js +6 -4
- package/dist/search.js +3 -2
- package/package.json +4 -2
- package/dist/html/template-kind.d.ts +0 -1
- package/dist/html/template-kind.js +0 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
+
import { isIgnoredContentName } from './content-store.js';
|
|
2
3
|
import { inferDirectoryContentType } from './content-type.js';
|
|
3
4
|
import { getDirectoryIndexCandidates } from './directory-index.js';
|
|
4
5
|
import { extractManagedIndexEntries, getDocumentSummary, getDocumentTitle as getParsedDocumentTitle, parseMarkdownDocument, stripManagedIndexBlock, stripManagedIndexLinks, } from './markdown.js';
|
|
5
6
|
import { applyIndexTransforms, renderFooterOverride, renderHeaderOverride, renderPageWithPlugins, transformHtmlWithPlugins, } from './extensions.js';
|
|
6
7
|
import { handleApiRoute } from './api.js';
|
|
7
8
|
import { normalizeRequestPath, resolveRequest } from './router.js';
|
|
8
|
-
import { escapeHtml,
|
|
9
|
+
import { escapeHtml, renderListingArticleItems, renderDocument, } from '../html/template.js';
|
|
9
10
|
export async function handleSiteRequest(store, pathname, options) {
|
|
10
11
|
const plugins = options.plugins ?? [];
|
|
11
12
|
const searchEnabled = options.searchApi !== undefined;
|
|
@@ -21,7 +22,7 @@ export async function handleSiteRequest(store, pathname, options) {
|
|
|
21
22
|
return renderSitemap(store, options);
|
|
22
23
|
}
|
|
23
24
|
const resolved = resolveRequest(pathname);
|
|
24
|
-
const
|
|
25
|
+
const listingFragmentRequest = getListingFragmentRequest(options.searchParams);
|
|
25
26
|
const negotiatedMarkdown = shouldServeMarkdownForRequest(resolved, options.acceptHeader);
|
|
26
27
|
if (resolved.kind === 'not-found' || !resolved.sourcePath) {
|
|
27
28
|
const aliasRedirect = await tryRedirectAlias(store, pathname, options);
|
|
@@ -82,21 +83,16 @@ export async function handleSiteRequest(store, pathname, options) {
|
|
|
82
83
|
: isRootHomeRequest(resolved.requestPath) && navigation.items.length > 0
|
|
83
84
|
? stripManagedIndexLinks(entry.text, new Set(navigation.items.map((item) => item.href)))
|
|
84
85
|
: entry.text;
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return renderCatalogPostsFragment(catalogEntries, catalogFragmentRequest);
|
|
96
|
-
}
|
|
97
|
-
const documentBody = options.siteConfig.template === 'catalog'
|
|
98
|
-
? stripManagedIndexBlock(renderedBody)
|
|
99
|
-
: renderedBody;
|
|
86
|
+
const listingEntries = await applyIndexTransforms(extractManagedIndexEntries(renderedBody), plugins, {
|
|
87
|
+
mode: 'render',
|
|
88
|
+
requestPath: resolved.requestPath,
|
|
89
|
+
sourcePath: resolved.sourcePath,
|
|
90
|
+
siteConfig: options.siteConfig,
|
|
91
|
+
});
|
|
92
|
+
if (listingFragmentRequest !== null && listingEntries.length > 0) {
|
|
93
|
+
return renderListingPostsFragment(listingEntries, listingFragmentRequest);
|
|
94
|
+
}
|
|
95
|
+
const documentBody = listingEntries.length > 0 ? stripManagedIndexBlock(renderedBody) : renderedBody;
|
|
100
96
|
const renderedParsed = documentBody === entry.text
|
|
101
97
|
? parsed
|
|
102
98
|
: await parseMarkdownDocument(resolved.sourcePath, documentBody);
|
|
@@ -107,18 +103,19 @@ export async function handleSiteRequest(store, pathname, options) {
|
|
|
107
103
|
renderedParsed,
|
|
108
104
|
siteConfig: options.siteConfig,
|
|
109
105
|
topNav: navigation.items,
|
|
110
|
-
|
|
106
|
+
listingEntries,
|
|
111
107
|
searchEnabled,
|
|
112
108
|
plugins,
|
|
113
109
|
varyOnAccept: shouldVaryOnAccept(resolved),
|
|
114
110
|
});
|
|
115
111
|
}
|
|
116
|
-
function
|
|
117
|
-
|
|
112
|
+
function getListingFragmentRequest(searchParams) {
|
|
113
|
+
const format = searchParams?.get('listing-format') ?? searchParams?.get('catalog-format');
|
|
114
|
+
if (format !== 'posts') {
|
|
118
115
|
return null;
|
|
119
116
|
}
|
|
120
|
-
const offset = normalizeNonNegativeInteger(searchParams
|
|
121
|
-
const limit = normalizePositiveInteger(searchParams
|
|
117
|
+
const offset = normalizeNonNegativeInteger(searchParams?.get('listing-offset') ?? searchParams?.get('catalog-offset') ?? null);
|
|
118
|
+
const limit = normalizePositiveInteger(searchParams?.get('listing-limit') ?? searchParams?.get('catalog-limit') ?? null);
|
|
122
119
|
if (offset === null || limit === null) {
|
|
123
120
|
return null;
|
|
124
121
|
}
|
|
@@ -140,7 +137,7 @@ function normalizePositiveInteger(value) {
|
|
|
140
137
|
}
|
|
141
138
|
function buildPageRenderModel(options) {
|
|
142
139
|
return {
|
|
143
|
-
kind: options.
|
|
140
|
+
kind: options.listingEntries.length > 0 ? 'listing' : 'page',
|
|
144
141
|
requestPath: options.resolvedRequestPath,
|
|
145
142
|
sourcePath: options.sourcePath,
|
|
146
143
|
siteTitle: options.siteConfig.siteTitle,
|
|
@@ -158,8 +155,6 @@ function buildPageRenderModel(options) {
|
|
|
158
155
|
date: options.siteConfig.showDate === false ? undefined : options.parsed.meta.date,
|
|
159
156
|
showSummary: options.siteConfig.showSummary,
|
|
160
157
|
showDate: options.siteConfig.showDate,
|
|
161
|
-
theme: options.siteConfig.theme,
|
|
162
|
-
template: options.siteConfig.template,
|
|
163
158
|
topNav: options.topNav,
|
|
164
159
|
footerNav: options.siteConfig.footerNav,
|
|
165
160
|
footerText: options.siteConfig.footerText,
|
|
@@ -169,10 +164,10 @@ function buildPageRenderModel(options) {
|
|
|
169
164
|
stylesheetContent: options.siteConfig.stylesheetContent,
|
|
170
165
|
canonicalPath: getCanonicalHtmlPathForContentPath(options.sourcePath),
|
|
171
166
|
alternateMarkdownPath: getMarkdownRequestPathForContentPath(options.sourcePath),
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
167
|
+
listingEntries: options.listingEntries,
|
|
168
|
+
listingRequestPath: options.resolvedRequestPath,
|
|
169
|
+
listingInitialPostCount: options.siteConfig.listingInitialPostCount,
|
|
170
|
+
listingLoadMoreStep: options.siteConfig.listingLoadMoreStep,
|
|
176
171
|
searchEnabled: options.searchEnabled,
|
|
177
172
|
};
|
|
178
173
|
}
|
|
@@ -184,7 +179,7 @@ async function renderStructuredPage(options) {
|
|
|
184
179
|
parsed: options.parsed,
|
|
185
180
|
siteConfig: options.siteConfig,
|
|
186
181
|
topNav: options.topNav,
|
|
187
|
-
|
|
182
|
+
listingEntries: options.listingEntries,
|
|
188
183
|
searchEnabled: options.searchEnabled,
|
|
189
184
|
});
|
|
190
185
|
const renderContext = {
|
|
@@ -198,7 +193,7 @@ async function renderStructuredPage(options) {
|
|
|
198
193
|
};
|
|
199
194
|
const headerHtml = await renderHeaderOverride(options.plugins, currentContext);
|
|
200
195
|
const footerHtml = await renderFooterOverride(options.plugins, currentContext);
|
|
201
|
-
return
|
|
196
|
+
return renderDocument({
|
|
202
197
|
siteTitle: currentPage.siteTitle,
|
|
203
198
|
siteDescription: currentPage.siteDescription,
|
|
204
199
|
siteUrl: currentPage.siteUrl,
|
|
@@ -211,8 +206,6 @@ async function renderStructuredPage(options) {
|
|
|
211
206
|
date: currentPage.date,
|
|
212
207
|
showSummary: currentPage.showSummary,
|
|
213
208
|
showDate: currentPage.showDate,
|
|
214
|
-
theme: currentPage.theme,
|
|
215
|
-
template: currentPage.template,
|
|
216
209
|
topNav: currentPage.topNav,
|
|
217
210
|
footerNav: currentPage.footerNav,
|
|
218
211
|
footerText: currentPage.footerText,
|
|
@@ -221,14 +214,14 @@ async function renderStructuredPage(options) {
|
|
|
221
214
|
stylesheetContent: currentPage.stylesheetContent,
|
|
222
215
|
canonicalPath: currentPage.canonicalPath,
|
|
223
216
|
alternateMarkdownPath: currentPage.alternateMarkdownPath,
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
217
|
+
listingEntries: currentPage.listingEntries,
|
|
218
|
+
listingRequestPath: currentPage.listingRequestPath,
|
|
219
|
+
listingInitialPostCount: currentPage.listingInitialPostCount,
|
|
220
|
+
listingLoadMoreStep: currentPage.listingLoadMoreStep,
|
|
228
221
|
searchEnabled: currentPage.searchEnabled,
|
|
229
222
|
headerHtml,
|
|
230
223
|
footerHtml,
|
|
231
|
-
})
|
|
224
|
+
});
|
|
232
225
|
});
|
|
233
226
|
const finalHtml = await transformHtmlWithPlugins(renderedPage.html, options.plugins, {
|
|
234
227
|
page: renderedPage.page,
|
|
@@ -242,7 +235,7 @@ async function renderStructuredPage(options) {
|
|
|
242
235
|
body: finalHtml,
|
|
243
236
|
};
|
|
244
237
|
}
|
|
245
|
-
function
|
|
238
|
+
function renderListingPostsFragment(entries, request) {
|
|
246
239
|
const articles = entries.filter((entry) => entry.kind === 'article');
|
|
247
240
|
const visibleArticles = articles.slice(request.offset, request.offset + request.limit);
|
|
248
241
|
const nextOffset = request.offset + visibleArticles.length;
|
|
@@ -252,7 +245,7 @@ function renderCatalogPostsFragment(entries, request) {
|
|
|
252
245
|
'content-type': 'application/json; charset=utf-8',
|
|
253
246
|
},
|
|
254
247
|
body: JSON.stringify({
|
|
255
|
-
itemsHtml:
|
|
248
|
+
itemsHtml: renderListingArticleItems(visibleArticles),
|
|
256
249
|
hasMore: nextOffset < articles.length,
|
|
257
250
|
nextOffset,
|
|
258
251
|
}),
|
|
@@ -424,8 +417,6 @@ async function renderDirectoryListing(store, requestPath, siteConfig, searchEnab
|
|
|
424
417
|
body,
|
|
425
418
|
showSummary: false,
|
|
426
419
|
showDate: false,
|
|
427
|
-
theme: siteConfig.theme,
|
|
428
|
-
template: siteConfig.template,
|
|
429
420
|
topNav: navigation.items,
|
|
430
421
|
footerNav: siteConfig.footerNav,
|
|
431
422
|
footerText: siteConfig.footerText,
|
|
@@ -484,22 +475,17 @@ async function tryRenderAlternateDirectoryIndex(store, requestPath, options) {
|
|
|
484
475
|
: isRootHomeRequest(requestPath) && navigation.items.length > 0
|
|
485
476
|
? stripManagedIndexLinks(entry.text, new Set(navigation.items.map((item) => item.href)))
|
|
486
477
|
: entry.text;
|
|
487
|
-
const
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
return renderCatalogPostsFragment(catalogEntries, catalogFragmentRequest);
|
|
499
|
-
}
|
|
500
|
-
const documentBody = options.siteConfig.template === 'catalog'
|
|
501
|
-
? stripManagedIndexBlock(renderedBody)
|
|
502
|
-
: renderedBody;
|
|
478
|
+
const listingEntries = await applyIndexTransforms(extractManagedIndexEntries(renderedBody), plugins, {
|
|
479
|
+
mode: 'render',
|
|
480
|
+
requestPath,
|
|
481
|
+
sourcePath: candidatePath,
|
|
482
|
+
siteConfig: options.siteConfig,
|
|
483
|
+
});
|
|
484
|
+
const listingFragmentRequest = getListingFragmentRequest(options.searchParams);
|
|
485
|
+
if (listingFragmentRequest !== null && listingEntries.length > 0) {
|
|
486
|
+
return renderListingPostsFragment(listingEntries, listingFragmentRequest);
|
|
487
|
+
}
|
|
488
|
+
const documentBody = listingEntries.length > 0 ? stripManagedIndexBlock(renderedBody) : renderedBody;
|
|
503
489
|
const renderedParsed = documentBody === entry.text
|
|
504
490
|
? parsed
|
|
505
491
|
: await parseMarkdownDocument(candidatePath, documentBody);
|
|
@@ -510,7 +496,7 @@ async function tryRenderAlternateDirectoryIndex(store, requestPath, options) {
|
|
|
510
496
|
renderedParsed,
|
|
511
497
|
siteConfig: options.siteConfig,
|
|
512
498
|
topNav: navigation.items,
|
|
513
|
-
|
|
499
|
+
listingEntries,
|
|
514
500
|
searchEnabled: options.searchApi !== undefined,
|
|
515
501
|
plugins,
|
|
516
502
|
});
|
|
@@ -750,7 +736,7 @@ async function inspectDirectoryShape(store, directoryPath) {
|
|
|
750
736
|
let hasExtraMarkdownFiles = false;
|
|
751
737
|
let hasAssetFiles = false;
|
|
752
738
|
for (const entry of entries) {
|
|
753
|
-
if (entry.name
|
|
739
|
+
if (isIgnoredContentName(entry.name)) {
|
|
754
740
|
continue;
|
|
755
741
|
}
|
|
756
742
|
if (entry.kind === 'directory') {
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { ContentStore } from './content-store.js';
|
|
2
2
|
import type { MdoPlugin } from './extensions.js';
|
|
3
|
-
import type { TemplateName } from '../html/template-kind.js';
|
|
4
|
-
import type { BuiltInThemeName } from '../html/theme.js';
|
|
5
3
|
export interface SiteNavItem {
|
|
6
4
|
label: string;
|
|
7
5
|
href: string;
|
|
@@ -29,16 +27,14 @@ export interface SiteConfig {
|
|
|
29
27
|
showDate?: boolean;
|
|
30
28
|
showSummary?: boolean;
|
|
31
29
|
stylesheet?: string;
|
|
32
|
-
theme?: BuiltInThemeName;
|
|
33
|
-
template?: TemplateName;
|
|
34
30
|
topNav?: SiteNavItem[];
|
|
35
31
|
footerNav?: SiteNavItem[];
|
|
36
32
|
footerText?: string;
|
|
37
33
|
socialLinks?: SiteSocialLink[];
|
|
38
34
|
editLink?: EditLinkConfig;
|
|
39
35
|
showHomeIndex?: boolean;
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
listingInitialPostCount?: number;
|
|
37
|
+
listingLoadMoreStep?: number;
|
|
42
38
|
}
|
|
43
39
|
export interface UserSiteConfig extends SiteConfig {
|
|
44
40
|
plugins?: MdoPlugin[];
|
|
@@ -52,16 +48,14 @@ export interface ResolvedSiteConfig {
|
|
|
52
48
|
logo?: SiteLogo;
|
|
53
49
|
showDate: boolean;
|
|
54
50
|
showSummary: boolean;
|
|
55
|
-
theme: BuiltInThemeName;
|
|
56
|
-
template: TemplateName;
|
|
57
51
|
topNav: SiteNavItem[];
|
|
58
52
|
footerNav: SiteNavItem[];
|
|
59
53
|
footerText?: string;
|
|
60
54
|
socialLinks: SiteSocialLink[];
|
|
61
55
|
editLink?: EditLinkConfig;
|
|
62
56
|
showHomeIndex: boolean;
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
listingInitialPostCount: number;
|
|
58
|
+
listingLoadMoreStep: number;
|
|
65
59
|
stylesheetContent?: string;
|
|
66
60
|
siteTitleConfigured: boolean;
|
|
67
61
|
siteDescriptionConfigured: boolean;
|
package/dist/core/site-config.js
CHANGED
|
@@ -14,6 +14,7 @@ export async function loadUserSiteConfig(options = {}) {
|
|
|
14
14
|
? path.resolve(cwd, options.configPath)
|
|
15
15
|
: await resolveDefaultConfigPath(cwd, rootDir);
|
|
16
16
|
const parsedConfig = await loadConfigSource(configFilePath);
|
|
17
|
+
const legacyConfig = parsedConfig;
|
|
17
18
|
const stylesheetPath = parsedConfig.stylesheet
|
|
18
19
|
? path.resolve(path.dirname(configFilePath), parsedConfig.stylesheet)
|
|
19
20
|
: null;
|
|
@@ -34,8 +35,6 @@ export async function loadUserSiteConfig(options = {}) {
|
|
|
34
35
|
logo: normalizeLogo(parsedConfig.logo),
|
|
35
36
|
showDate: parsedConfig.showDate ?? true,
|
|
36
37
|
showSummary: parsedConfig.showSummary ?? true,
|
|
37
|
-
theme: isBuiltInThemeName(parsedConfig.theme) ? parsedConfig.theme : 'paper',
|
|
38
|
-
template: isTemplateName(parsedConfig.template) ? parsedConfig.template : 'document',
|
|
39
38
|
topNav: normalizeTopNav(parsedConfig.topNav),
|
|
40
39
|
footerNav: normalizeTopNav(parsedConfig.footerNav),
|
|
41
40
|
footerText: typeof parsedConfig.footerText === 'string' && parsedConfig.footerText !== ''
|
|
@@ -46,13 +45,14 @@ export async function loadUserSiteConfig(options = {}) {
|
|
|
46
45
|
showHomeIndex: typeof parsedConfig.showHomeIndex === 'boolean'
|
|
47
46
|
? parsedConfig.showHomeIndex
|
|
48
47
|
: normalizeTopNav(parsedConfig.topNav).length === 0,
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
listingInitialPostCount: normalizePositiveInteger(parsedConfig.listingInitialPostCount ?? legacyConfig.catalogInitialPostCount, 10),
|
|
49
|
+
listingLoadMoreStep: normalizePositiveInteger(parsedConfig.listingLoadMoreStep ?? legacyConfig.catalogLoadMoreStep, 10),
|
|
51
50
|
stylesheetContent,
|
|
52
51
|
siteTitleConfigured: typeof parsedConfig.siteTitle === 'string' && parsedConfig.siteTitle !== '',
|
|
53
52
|
siteDescriptionConfigured: typeof parsedConfig.siteDescription === 'string' &&
|
|
54
53
|
parsedConfig.siteDescription !== '',
|
|
55
54
|
};
|
|
55
|
+
warnOnLegacyConfig(legacyConfig, configFilePath);
|
|
56
56
|
return {
|
|
57
57
|
siteConfig,
|
|
58
58
|
plugins: Array.isArray(parsedConfig.plugins) ? parsedConfig.plugins : [],
|
|
@@ -93,12 +93,6 @@ async function resolveDefaultConfigPath(cwd, rootDir) {
|
|
|
93
93
|
}
|
|
94
94
|
return (await findConfigPath(cwd)) ?? path.join(cwd, 'mdorigin.config.json');
|
|
95
95
|
}
|
|
96
|
-
function isBuiltInThemeName(value) {
|
|
97
|
-
return value === 'paper' || value === 'atlas' || value === 'gazette';
|
|
98
|
-
}
|
|
99
|
-
function isTemplateName(value) {
|
|
100
|
-
return value === 'document' || value === 'catalog';
|
|
101
|
-
}
|
|
102
96
|
function isNodeNotFound(error) {
|
|
103
97
|
return (typeof error === 'object' &&
|
|
104
98
|
error !== null &&
|
|
@@ -275,3 +269,17 @@ function normalizeSiteHref(value) {
|
|
|
275
269
|
}
|
|
276
270
|
return `/${value.replace(/^\.?\//, '')}`;
|
|
277
271
|
}
|
|
272
|
+
function warnOnLegacyConfig(config, configFilePath) {
|
|
273
|
+
if ('theme' in config) {
|
|
274
|
+
console.warn(`[mdorigin] ${configFilePath}: "theme" is deprecated and ignored. mdorigin now uses a single built-in atlas presentation.`);
|
|
275
|
+
}
|
|
276
|
+
if ('template' in config) {
|
|
277
|
+
console.warn(`[mdorigin] ${configFilePath}: "template" is deprecated and ignored. Listing behavior is now part of the default presentation.`);
|
|
278
|
+
}
|
|
279
|
+
if ('catalogInitialPostCount' in config) {
|
|
280
|
+
console.warn(`[mdorigin] ${configFilePath}: "catalogInitialPostCount" is deprecated. Use "listingInitialPostCount" instead.`);
|
|
281
|
+
}
|
|
282
|
+
if ('catalogLoadMoreStep' in config) {
|
|
283
|
+
console.warn(`[mdorigin] ${configFilePath}: "catalogLoadMoreStep" is deprecated. Use "listingLoadMoreStep" instead.`);
|
|
284
|
+
}
|
|
285
|
+
}
|
package/dist/html/template.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { SiteLogo, SiteNavItem, SiteSocialLink } from '../core/site-config.js';
|
|
2
2
|
import type { ManagedIndexEntry } from '../core/markdown.js';
|
|
3
|
-
import type { TemplateName } from './template-kind.js';
|
|
4
|
-
import { type BuiltInThemeName } from './theme.js';
|
|
5
3
|
export interface RenderDocumentOptions {
|
|
6
4
|
siteTitle: string;
|
|
7
5
|
siteDescription?: string;
|
|
@@ -15,8 +13,6 @@ export interface RenderDocumentOptions {
|
|
|
15
13
|
date?: string;
|
|
16
14
|
showSummary?: boolean;
|
|
17
15
|
showDate?: boolean;
|
|
18
|
-
theme: BuiltInThemeName;
|
|
19
|
-
template: TemplateName;
|
|
20
16
|
topNav?: SiteNavItem[];
|
|
21
17
|
footerNav?: SiteNavItem[];
|
|
22
18
|
footerText?: string;
|
|
@@ -25,14 +21,14 @@ export interface RenderDocumentOptions {
|
|
|
25
21
|
stylesheetContent?: string;
|
|
26
22
|
canonicalPath?: string;
|
|
27
23
|
alternateMarkdownPath?: string;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
listingEntries?: ManagedIndexEntry[];
|
|
25
|
+
listingRequestPath?: string;
|
|
26
|
+
listingInitialPostCount?: number;
|
|
27
|
+
listingLoadMoreStep?: number;
|
|
32
28
|
searchEnabled?: boolean;
|
|
33
29
|
headerHtml?: string;
|
|
34
30
|
footerHtml?: string;
|
|
35
31
|
}
|
|
36
32
|
export declare function renderDocument(options: RenderDocumentOptions): string;
|
|
37
33
|
export declare function escapeHtml(value: string): string;
|
|
38
|
-
export declare function
|
|
34
|
+
export declare function renderListingArticleItems(entries: readonly ManagedIndexEntry[]): string;
|
package/dist/html/template.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getDefaultThemeStyles } from './theme.js';
|
|
2
2
|
export function renderDocument(options) {
|
|
3
3
|
const title = escapeHtml(options.title);
|
|
4
4
|
const siteTitle = escapeHtml(options.siteTitle);
|
|
@@ -25,7 +25,7 @@ export function renderDocument(options) {
|
|
|
25
25
|
const alternateMarkdownMeta = options.alternateMarkdownPath
|
|
26
26
|
? `<link rel="alternate" type="text/markdown" href="${escapeHtml(options.alternateMarkdownPath)}">`
|
|
27
27
|
: '';
|
|
28
|
-
const stylesheetBlock = `<style>${
|
|
28
|
+
const stylesheetBlock = `<style>${getDefaultThemeStyles()}${options.stylesheetContent ? `\n${options.stylesheetContent}` : ''}</style>`;
|
|
29
29
|
const navBlock = options.topNav && options.topNav.length > 0
|
|
30
30
|
? `<nav class="site-nav"><ul>${options.topNav
|
|
31
31
|
.map((item) => `<li><a href="${escapeHtml(item.href)}">${escapeHtml(item.label)}</a></li>`)
|
|
@@ -69,20 +69,26 @@ export function renderDocument(options) {
|
|
|
69
69
|
const editLinkBlock = options.editLinkHref
|
|
70
70
|
? `<a class="site-footer__edit-link" href="${escapeHtml(options.editLinkHref)}">Edit this page</a>`
|
|
71
71
|
: '';
|
|
72
|
+
const markdownViewBlock = options.alternateMarkdownPath
|
|
73
|
+
? `<a class="site-footer__markdown-link" href="${escapeHtml(options.alternateMarkdownPath)}" aria-label="View Markdown source">MD View</a>`
|
|
74
|
+
: '';
|
|
75
|
+
const footerActionsBlock = markdownViewBlock || editLinkBlock
|
|
76
|
+
? `<div class="site-footer__actions">${markdownViewBlock}${editLinkBlock}</div>`
|
|
77
|
+
: '';
|
|
72
78
|
const footerTextBlock = options.footerText
|
|
73
79
|
? `<p class="site-footer__text">${escapeHtml(options.footerText)}</p>`
|
|
74
80
|
: '';
|
|
75
|
-
const footerMetaBlock = socialLinksBlock ||
|
|
76
|
-
? `<div class="site-footer__meta">${socialLinksBlock}${
|
|
81
|
+
const footerMetaBlock = socialLinksBlock || footerActionsBlock
|
|
82
|
+
? `<div class="site-footer__meta">${socialLinksBlock}${footerActionsBlock}</div>`
|
|
77
83
|
: '';
|
|
78
84
|
const footerBlock = footerNavBlock || footerTextBlock || footerMetaBlock
|
|
79
85
|
? `<footer class="site-footer"><div class="site-footer__inner">${footerNavBlock}${footerTextBlock}${footerMetaBlock}</div></footer>`
|
|
80
86
|
: '';
|
|
81
|
-
const articleBody = options.
|
|
82
|
-
?
|
|
83
|
-
requestPath: options.
|
|
84
|
-
initialPostCount: options.
|
|
85
|
-
loadMoreStep: options.
|
|
87
|
+
const articleBody = options.listingEntries && options.listingEntries.length > 0
|
|
88
|
+
? renderListingArticle(options.body, options.listingEntries, {
|
|
89
|
+
requestPath: options.listingRequestPath ?? '/',
|
|
90
|
+
initialPostCount: options.listingInitialPostCount ?? 10,
|
|
91
|
+
loadMoreStep: options.listingLoadMoreStep ?? 10,
|
|
86
92
|
})
|
|
87
93
|
: options.body;
|
|
88
94
|
const searchScript = options.searchEnabled ? renderSearchScript() : '';
|
|
@@ -103,7 +109,7 @@ export function renderDocument(options) {
|
|
|
103
109
|
alternateMarkdownMeta,
|
|
104
110
|
stylesheetBlock,
|
|
105
111
|
'</head>',
|
|
106
|
-
|
|
112
|
+
'<body>',
|
|
107
113
|
headerBlock,
|
|
108
114
|
'<main>',
|
|
109
115
|
`<article>${articleBody}</article>`,
|
|
@@ -153,7 +159,7 @@ function renderSocialIcon(icon) {
|
|
|
153
159
|
function iconSvg(pathData) {
|
|
154
160
|
return `<svg viewBox="0 0 24 24" aria-hidden="true"><path d="${pathData}"></path></svg>`;
|
|
155
161
|
}
|
|
156
|
-
function
|
|
162
|
+
function renderListingArticle(body, entries, options) {
|
|
157
163
|
if (entries.length === 0) {
|
|
158
164
|
return body;
|
|
159
165
|
}
|
|
@@ -164,10 +170,10 @@ function renderCatalogArticle(body, entries, options) {
|
|
|
164
170
|
const shouldLoadMore = articles.length > visibleArticles.length;
|
|
165
171
|
return [
|
|
166
172
|
`<div class="catalog-page__body">${body}</div>`,
|
|
167
|
-
'<section class="catalog-page" aria-label="
|
|
168
|
-
directories.length > 0 ?
|
|
173
|
+
'<section class="catalog-page" aria-label="Content listing">',
|
|
174
|
+
directories.length > 0 ? renderListingDirectories(directories) : '',
|
|
169
175
|
articles.length > 0
|
|
170
|
-
?
|
|
176
|
+
? renderListingArticles(visibleArticles, {
|
|
171
177
|
requestPath: options.requestPath,
|
|
172
178
|
nextOffset: visibleArticles.length,
|
|
173
179
|
loadMoreStep: options.loadMoreStep,
|
|
@@ -175,10 +181,10 @@ function renderCatalogArticle(body, entries, options) {
|
|
|
175
181
|
})
|
|
176
182
|
: '',
|
|
177
183
|
'</section>',
|
|
178
|
-
shouldLoadMore ?
|
|
184
|
+
shouldLoadMore ? renderListingLoadMoreScript() : '',
|
|
179
185
|
].join('');
|
|
180
186
|
}
|
|
181
|
-
function
|
|
187
|
+
function renderListingDirectories(entries) {
|
|
182
188
|
return [
|
|
183
189
|
'<div class="catalog-list catalog-list--directories">',
|
|
184
190
|
...entries.map((entry) => `<a class="catalog-item catalog-item--directory" href="${escapeHtml(entry.href)}"><strong class="catalog-item__title">${escapeHtml(entry.title)}</strong>${entry.detail
|
|
@@ -187,28 +193,28 @@ function renderCatalogDirectories(entries) {
|
|
|
187
193
|
'</div>',
|
|
188
194
|
].join('');
|
|
189
195
|
}
|
|
190
|
-
export function
|
|
196
|
+
export function renderListingArticleItems(entries) {
|
|
191
197
|
return entries
|
|
192
198
|
.map((entry) => `<a class="catalog-item" href="${escapeHtml(entry.href)}"><strong class="catalog-item__title">${escapeHtml(entry.title)}</strong>${entry.detail
|
|
193
199
|
? `<span class="catalog-item__detail">${escapeHtml(entry.detail)}</span>`
|
|
194
200
|
: ''}</a>`)
|
|
195
201
|
.join('');
|
|
196
202
|
}
|
|
197
|
-
function
|
|
203
|
+
function renderListingArticles(entries, options) {
|
|
198
204
|
return [
|
|
199
|
-
'<div class="catalog-list" data-
|
|
200
|
-
|
|
205
|
+
'<div class="catalog-list" data-listing-articles>',
|
|
206
|
+
renderListingArticleItems(entries),
|
|
201
207
|
'</div>',
|
|
202
208
|
options.hasMore
|
|
203
|
-
? `<div class="catalog-load-more"><button type="button" class="catalog-load-more__button" data-
|
|
209
|
+
? `<div class="catalog-load-more"><button type="button" class="catalog-load-more__button" data-listing-load-more data-request-path="${escapeHtml(options.requestPath)}" data-next-offset="${escapeHtml(String(options.nextOffset))}" data-load-more-step="${escapeHtml(String(options.loadMoreStep))}">Load more</button></div>`
|
|
204
210
|
: '',
|
|
205
211
|
].join('');
|
|
206
212
|
}
|
|
207
|
-
function
|
|
213
|
+
function renderListingLoadMoreScript() {
|
|
208
214
|
return `<script>
|
|
209
215
|
(() => {
|
|
210
|
-
const button = document.querySelector('[data-
|
|
211
|
-
const list = document.querySelector('[data-
|
|
216
|
+
const button = document.querySelector('[data-listing-load-more]');
|
|
217
|
+
const list = document.querySelector('[data-listing-articles]');
|
|
212
218
|
if (!(button instanceof HTMLButtonElement) || !(list instanceof HTMLElement)) {
|
|
213
219
|
return;
|
|
214
220
|
}
|
|
@@ -227,9 +233,9 @@ function renderCatalogLoadMoreScript() {
|
|
|
227
233
|
|
|
228
234
|
try {
|
|
229
235
|
const url = new URL(requestPath, window.location.origin);
|
|
230
|
-
url.searchParams.set('
|
|
231
|
-
url.searchParams.set('
|
|
232
|
-
url.searchParams.set('
|
|
236
|
+
url.searchParams.set('listing-format', 'posts');
|
|
237
|
+
url.searchParams.set('listing-offset', nextOffset);
|
|
238
|
+
url.searchParams.set('listing-limit', loadMoreStep);
|
|
233
239
|
|
|
234
240
|
const response = await fetch(url.toString(), {
|
|
235
241
|
headers: { Accept: 'application/json' },
|
package/dist/html/theme.d.ts
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export declare function getBuiltInThemeStyles(theme: BuiltInThemeName): string;
|
|
1
|
+
export declare function getDefaultThemeStyles(): string;
|